@smarterplan/ngx-smarterplan-core 1.4.6 → 1.4.7
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/helpers.service.mjs +27 -20
- package/esm2022/lib/mattertagData.mjs +84 -84
- package/esm2022/lib/pipes/time-date-to-local-string.pipe.mjs +3 -8
- package/esm2022/lib/services/locale.service.mjs +3 -5
- package/esm2022/lib/services/matterport-import.service.mjs +3 -3
- package/esm2022/lib/services/matterport-measurement.service.mjs +78 -0
- package/esm2022/lib/services/matterport-navigation.service.mjs +157 -0
- package/esm2022/lib/services/matterport-object3d.service.mjs +234 -0
- package/esm2022/lib/services/matterport-pointer.service.mjs +130 -0
- package/esm2022/lib/services/matterport-tag.service.mjs +458 -0
- package/esm2022/lib/services/matterport.service.mjs +427 -988
- package/esm2022/lib/services/models/equipment.service.mjs +3 -4
- package/esm2022/lib/services/models/feature.service.mjs +3 -3
- package/esm2022/lib/services/models/measurement.service.mjs +3 -3
- package/esm2022/lib/services/models/ticket.service.mjs +3 -4
- package/esm2022/lib/services/navigator.service.mjs +10 -2
- package/esm2022/lib/services/tag.service.mjs +45 -19
- package/esm2022/lib/services/viewer.service.mjs +51 -16
- package/esm2022/lib/types.service.mjs +1 -1
- package/fesm2022/smarterplan-ngx-smarterplan-core.mjs +2028 -1490
- package/fesm2022/smarterplan-ngx-smarterplan-core.mjs.map +1 -1
- package/lib/helpers.service.d.ts +6 -0
- package/lib/mattertagData.d.ts +52 -10
- package/lib/services/matterport-measurement.service.d.ts +35 -0
- package/lib/services/matterport-navigation.service.d.ts +38 -0
- package/lib/services/matterport-object3d.service.d.ts +31 -0
- package/lib/services/matterport-pointer.service.d.ts +31 -0
- package/lib/services/matterport-tag.service.d.ts +104 -0
- package/lib/services/matterport.service.d.ts +91 -92
- package/lib/services/models/equipment.service.d.ts +2 -2
- package/lib/services/models/feature.service.d.ts +2 -2
- package/lib/services/models/measurement.service.d.ts +2 -2
- package/lib/services/models/ticket.service.d.ts +2 -2
- package/lib/services/tag.service.d.ts +4 -0
- package/lib/services/viewer.service.d.ts +1 -1
- package/lib/types.service.d.ts +2 -0
- package/package.json +1 -1
- package/esm2022/lib/matterport-extensions/hsl-loader/HlsLoader.mjs +0 -66
- package/esm2022/lib/matterport-extensions/video-renderer/VideoRenderer.mjs +0 -63
- package/lib/matterport-extensions/hsl-loader/HlsLoader.d.ts +0 -26
- package/lib/matterport-extensions/video-renderer/VideoRenderer.d.ts +0 -26
|
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { Injectable, Input, Component, Inject, EventEmitter, isDevMode, Output, Pipe, ViewChild, NgModule } from '@angular/core';
|
|
3
3
|
import * as i1 from '@ngx-translate/core';
|
|
4
4
|
import { TranslateModule } from '@ngx-translate/core';
|
|
5
|
-
import { Subject, takeUntil, Observable } from 'rxjs';
|
|
5
|
+
import { Subject, BehaviorSubject, takeUntil, Observable } from 'rxjs';
|
|
6
6
|
import * as i1$2 from '@ng-bootstrap/ng-bootstrap';
|
|
7
7
|
import { NgbDate, NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
|
8
8
|
import * as i1$1 from '@angular/router';
|
|
@@ -1964,62 +1964,43 @@ class MattertagData {
|
|
|
1964
1964
|
mediaSrc;
|
|
1965
1965
|
sweepID;
|
|
1966
1966
|
customIconIndex = 0;
|
|
1967
|
-
rotation;
|
|
1967
|
+
rotation = null;
|
|
1968
1968
|
poi;
|
|
1969
|
+
matterportSid = null;
|
|
1969
1970
|
constructor(type) {
|
|
1970
1971
|
this.setType(type);
|
|
1971
1972
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
setType(type) {
|
|
1976
|
-
this.type = type;
|
|
1977
|
-
}
|
|
1973
|
+
/*---------------------------------------------------------------------------
|
|
1974
|
+
Setters
|
|
1975
|
+
---------------------------------------------------------------------------*/
|
|
1976
|
+
setType(type) { this.type = type; }
|
|
1978
1977
|
setObject(object, tagType) {
|
|
1979
1978
|
this.object = object;
|
|
1980
1979
|
this.setElementID(object.id);
|
|
1981
1980
|
this.setType(tagType);
|
|
1982
1981
|
}
|
|
1983
|
-
setElementID(
|
|
1984
|
-
this.elementID = ticketID;
|
|
1985
|
-
}
|
|
1982
|
+
setElementID(id) { this.elementID = id; }
|
|
1986
1983
|
setPosition(position) {
|
|
1987
1984
|
this.position = position;
|
|
1988
1985
|
}
|
|
1989
1986
|
setNormal(normal) {
|
|
1990
1987
|
this.normal = normal;
|
|
1991
1988
|
}
|
|
1992
|
-
setMediaSource(source) {
|
|
1993
|
-
|
|
1994
|
-
}
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
}
|
|
2001
|
-
setPoi(poi) {
|
|
2002
|
-
this.poi = poi;
|
|
2003
|
-
}
|
|
2004
|
-
/*-----------------------------------------------------------------------------
|
|
2005
|
-
Getters
|
|
2006
|
-
------------------------------------------------------------------------------*/
|
|
2007
|
-
// MattertagData
|
|
1989
|
+
setMediaSource(source) { this.mediaSrc = source; }
|
|
1990
|
+
setSweepID(sweepID) { this.sweepID = sweepID; }
|
|
1991
|
+
setRotation(rotation) { this.rotation = rotation; }
|
|
1992
|
+
setPoi(poi) { this.poi = poi; }
|
|
1993
|
+
setMatterportSid(sid) { this.matterportSid = sid; }
|
|
1994
|
+
/*---------------------------------------------------------------------------
|
|
1995
|
+
Getters
|
|
1996
|
+
---------------------------------------------------------------------------*/
|
|
2008
1997
|
getData() {
|
|
2009
1998
|
let label = "New Tag";
|
|
2010
1999
|
switch (this.type) {
|
|
2011
2000
|
case PoiType.TICKET:
|
|
2012
|
-
label = this.object ? "" : "New Tag"; // if the object exists we inject title in html
|
|
2013
|
-
break;
|
|
2014
2001
|
case PoiType.EQUIPMENT:
|
|
2015
|
-
label = this.object ? "" : "New Tag";
|
|
2016
|
-
break;
|
|
2017
2002
|
case PoiType.MEASURE:
|
|
2018
|
-
label = this.object ? "" : "New Tag";
|
|
2019
|
-
break;
|
|
2020
2003
|
case PoiType.DATA:
|
|
2021
|
-
label = this.object ? "" : "New Tag";
|
|
2022
|
-
break;
|
|
2023
2004
|
case PoiType.DESK:
|
|
2024
2005
|
label = this.object ? "" : "New Tag";
|
|
2025
2006
|
break;
|
|
@@ -2031,47 +2012,73 @@ class MattertagData {
|
|
|
2031
2012
|
break;
|
|
2032
2013
|
default:
|
|
2033
2014
|
label = "New Tag";
|
|
2034
|
-
break;
|
|
2035
2015
|
}
|
|
2036
|
-
|
|
2016
|
+
return {
|
|
2037
2017
|
label,
|
|
2038
2018
|
description: "",
|
|
2039
|
-
anchorPosition: {
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2019
|
+
anchorPosition: { ...this.position },
|
|
2020
|
+
stemVector: this.getStemVector(),
|
|
2021
|
+
color: { r: 1, g: 1, b: 1 },
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
2024
|
+
/**
|
|
2025
|
+
* Get the descriptor for sdk.Tag.add(...descriptor)
|
|
2026
|
+
* Format : [{ label, description, anchorPosition, stemVector, color, id? }]
|
|
2027
|
+
* If matterportSid is defined (already known tag) we send it so the SDK
|
|
2028
|
+
* reuse it instead of trying to create a new one and generate an error : "already in use".
|
|
2029
|
+
*/
|
|
2030
|
+
getMattertagDescriptor() {
|
|
2031
|
+
const base = this.getData();
|
|
2032
|
+
const descriptor = { ...base };
|
|
2033
|
+
if (this.matterportSid) {
|
|
2034
|
+
descriptor['id'] = this.matterportSid;
|
|
2035
|
+
}
|
|
2036
|
+
return [descriptor];
|
|
2037
|
+
}
|
|
2038
|
+
/**
|
|
2039
|
+
* Get data for sdk.Tag.editPosition() or sdk.Tag.editBillboard().
|
|
2040
|
+
*/
|
|
2041
|
+
getTagSdkData() {
|
|
2042
|
+
return {
|
|
2043
|
+
anchorPosition: { ...this.position },
|
|
2044
|
+
stemVector: this.getStemVector(),
|
|
2059
2045
|
};
|
|
2060
|
-
return data;
|
|
2061
2046
|
}
|
|
2062
|
-
|
|
2063
|
-
|
|
2047
|
+
/** Load the matterportSid from the poi metadata */
|
|
2048
|
+
loadSidFromPoi(poi) {
|
|
2049
|
+
if (!poi?.metadata)
|
|
2050
|
+
return;
|
|
2051
|
+
try {
|
|
2052
|
+
const meta = JSON.parse(poi.metadata);
|
|
2053
|
+
if (meta?.sid && typeof meta.sid === 'string') {
|
|
2054
|
+
this.matterportSid = meta.sid;
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
catch { }
|
|
2064
2058
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2059
|
+
/** Get the stem vector for the tag */
|
|
2060
|
+
getStemVector() {
|
|
2061
|
+
return {
|
|
2062
|
+
x: this.normal.x * 0.3,
|
|
2063
|
+
y: this.normal.y * 0.3,
|
|
2064
|
+
z: this.normal.z * 0.3,
|
|
2065
|
+
};
|
|
2067
2066
|
}
|
|
2067
|
+
getType() { return this.type; }
|
|
2068
|
+
getNormal() { return this.normal; }
|
|
2069
|
+
getPosition() { return this.position; }
|
|
2070
|
+
getSweepID() { return this.sweepID; }
|
|
2071
|
+
getObject() { return this.object; }
|
|
2072
|
+
getRotation() { return this.rotation; }
|
|
2073
|
+
getPoi() { return this.poi; }
|
|
2074
|
+
getMatterportSid() { return this.matterportSid; }
|
|
2075
|
+
/** Get the action mode for the tag */
|
|
2068
2076
|
getCallbackActionMode() {
|
|
2069
2077
|
switch (this.type) {
|
|
2070
2078
|
case PoiType.TICKET:
|
|
2071
2079
|
return this.object ? MattertagActionMode.POSITION_TICKET : MattertagActionMode.ADD_TICKET;
|
|
2072
2080
|
case PoiType.OBJECT3D:
|
|
2073
2081
|
return MattertagActionMode.POSITION_OBJECT3D;
|
|
2074
|
-
// return this.object ? MattertagActionMode.POSITION_OBJECT3D : MattertagActionMode.ADD_OBJECT3D;
|
|
2075
2082
|
case PoiType.EQUIPMENT:
|
|
2076
2083
|
return this.object ? MattertagActionMode.POSITION_EQUIPMENT : MattertagActionMode.ADD_EQUIPMENT;
|
|
2077
2084
|
case PoiType.DATA:
|
|
@@ -2084,448 +2091,1471 @@ class MattertagData {
|
|
|
2084
2091
|
return MattertagActionMode.ADD_TICKET;
|
|
2085
2092
|
}
|
|
2086
2093
|
}
|
|
2094
|
+
/** Get the icon for the tag */
|
|
2087
2095
|
getIcon() {
|
|
2088
2096
|
switch (this.type) {
|
|
2089
|
-
case PoiType.TICKET:
|
|
2090
|
-
|
|
2091
|
-
case PoiType.
|
|
2092
|
-
|
|
2093
|
-
case PoiType.
|
|
2094
|
-
|
|
2097
|
+
case PoiType.TICKET: return "icon_ticket.png";
|
|
2098
|
+
case PoiType.EQUIPMENT: return "icon_equipment.png";
|
|
2099
|
+
case PoiType.OBJECT3D: return "icon_object3d.png";
|
|
2100
|
+
case PoiType.MEASURE: return "icon_measure.png";
|
|
2101
|
+
case PoiType.DATA: return "icon_data.png";
|
|
2102
|
+
case PoiType.DESK: return "icon_data.png";
|
|
2103
|
+
case PoiType.ROOM: return "";
|
|
2104
|
+
default: return "";
|
|
2095
2105
|
}
|
|
2096
|
-
return "";
|
|
2097
2106
|
}
|
|
2107
|
+
/** Get the coordinate string for the tag */
|
|
2098
2108
|
getCoordinateString() {
|
|
2099
2109
|
return JSON.stringify({
|
|
2100
2110
|
x: this.position.x,
|
|
2101
2111
|
y: this.position.y,
|
|
2102
2112
|
z: this.position.z,
|
|
2103
|
-
xRotation: this.rotation
|
|
2104
|
-
yRotation: this.rotation
|
|
2113
|
+
xRotation: this.rotation?.x ?? null,
|
|
2114
|
+
yRotation: this.rotation?.y ?? null,
|
|
2105
2115
|
});
|
|
2106
2116
|
}
|
|
2117
|
+
/** Get the metadata string for the tag */
|
|
2107
2118
|
getMetadataString() {
|
|
2108
2119
|
return JSON.stringify({
|
|
2109
2120
|
icon: this.getIcon(),
|
|
2110
2121
|
normal: this.getNormal(),
|
|
2122
|
+
sid: this.matterportSid,
|
|
2111
2123
|
});
|
|
2112
2124
|
}
|
|
2113
|
-
getSweepID() {
|
|
2114
|
-
return this.sweepID;
|
|
2115
|
-
}
|
|
2116
|
-
getObject() {
|
|
2117
|
-
return this.object;
|
|
2118
|
-
}
|
|
2119
|
-
getRotation() {
|
|
2120
|
-
return this.rotation;
|
|
2121
|
-
}
|
|
2122
|
-
getPoi() {
|
|
2123
|
-
return this.poi;
|
|
2124
|
-
}
|
|
2125
2125
|
}
|
|
2126
2126
|
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
visible: false,
|
|
2127
|
+
class BaseVisibilityService {
|
|
2128
|
+
detailShowing = new Subject();
|
|
2129
|
+
isChangePositionVisible = new Subject();
|
|
2130
|
+
constructor() { }
|
|
2131
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BaseVisibilityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2132
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BaseVisibilityService, providedIn: 'root' });
|
|
2133
|
+
}
|
|
2134
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BaseVisibilityService, decorators: [{
|
|
2135
|
+
type: Injectable,
|
|
2136
|
+
args: [{
|
|
2137
|
+
providedIn: 'root',
|
|
2138
|
+
}]
|
|
2139
|
+
}], ctorParameters: () => [] });
|
|
2140
|
+
|
|
2141
|
+
class MatterportMeasurementService {
|
|
2142
|
+
router;
|
|
2143
|
+
lastMeasure = [];
|
|
2144
|
+
distancesLastMeasure = [];
|
|
2145
|
+
lastScreenshotUri;
|
|
2146
|
+
resolution = {
|
|
2147
|
+
width: 500,
|
|
2148
|
+
height: 600,
|
|
2150
2149
|
};
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2150
|
+
visibility = {
|
|
2151
|
+
mattertags: false,
|
|
2152
|
+
sweeps: true,
|
|
2154
2153
|
};
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
this.context = {
|
|
2158
|
-
root: modelNode
|
|
2159
|
-
};
|
|
2160
|
-
}
|
|
2161
|
-
this.inputs.texture = inputTexture;
|
|
2162
|
-
const root = this.context.root;
|
|
2163
|
-
const THREE = this.context.three;
|
|
2164
|
-
this.planeRenderer = plane;
|
|
2165
|
-
this.planeRenderer.outputs.objectRoot.translateZ(0.05);
|
|
2166
|
-
this.planeRenderer.outputs.objectRoot.translateY(0.4);
|
|
2167
|
-
this.planeRenderer.outputs.objectRoot.scale.set(0.5, 0.5, 0.5);
|
|
2168
|
-
// planeRenderer.inputs.localPosition.z = 0.05;
|
|
2169
|
-
// planeRenderer.inputs.localPosition.y = 0.4;
|
|
2170
|
-
// planeRenderer.inputs.localScale = {x: 0.5, y: 0.5, z: 0.5};
|
|
2171
|
-
this.outputs.painter = this;
|
|
2172
|
-
this.mixer = new AnimationMixer(this.planeRenderer.outputs.objectRoot);
|
|
2173
|
-
const tm = 0.2;
|
|
2174
|
-
const positionTrack = new VectorKeyframeTrack('.scale', [0, tm], [
|
|
2175
|
-
0, 0, 0,
|
|
2176
|
-
0.5, 0.5, 0.5
|
|
2177
|
-
], InterpolateSmooth);
|
|
2178
|
-
this.onEnterClip = new AnimationClip(null, tm, [positionTrack]);
|
|
2154
|
+
constructor(router) {
|
|
2155
|
+
this.router = router;
|
|
2179
2156
|
}
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
if (m && m.map.source.data.outerHTML.indexOf('_5b76dbe388862300126c1e14') !== -1) {
|
|
2194
|
-
const newMaterial = new MeshBasicMaterial({ map: this.inputs.texture });
|
|
2195
|
-
this.mesh.material[idx] = newMaterial;
|
|
2196
|
-
}
|
|
2197
|
-
});
|
|
2198
|
-
}
|
|
2199
|
-
});
|
|
2200
|
-
// remove the line segments.
|
|
2201
|
-
lines.forEach((line) => {
|
|
2202
|
-
line.parent.remove(line);
|
|
2157
|
+
/**
|
|
2158
|
+
* Callback after measurement is performed
|
|
2159
|
+
*/
|
|
2160
|
+
getDistanceForLastMeasurement(sdk, currentSpaceID) {
|
|
2161
|
+
if (this.lastMeasure.length > 0) {
|
|
2162
|
+
const numberPoints = this.lastMeasure.length;
|
|
2163
|
+
this.distancesLastMeasure = [];
|
|
2164
|
+
for (let index = 1; index < numberPoints; index += 1) {
|
|
2165
|
+
const distance = getDistanceBetweenTwoPoints(this.lastMeasure[index - 1], this.lastMeasure[index]);
|
|
2166
|
+
this.distancesLastMeasure.push(distance);
|
|
2167
|
+
}
|
|
2168
|
+
this.takeScreenShot(sdk).then(() => {
|
|
2169
|
+
this.router.navigate([`visit/${currentSpaceID}/add_measurement`]);
|
|
2203
2170
|
});
|
|
2204
2171
|
}
|
|
2205
2172
|
}
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
const data = eventData;
|
|
2209
|
-
if (data.hover) {
|
|
2210
|
-
this.outputs.visible = true;
|
|
2211
|
-
const onEnterAction = this.mixer.clipAction(this.onEnterClip);
|
|
2212
|
-
onEnterAction.stop();
|
|
2213
|
-
onEnterAction.loop = LoopOnce;
|
|
2214
|
-
onEnterAction.clampWhenFinished = true;
|
|
2215
|
-
onEnterAction.play();
|
|
2216
|
-
}
|
|
2217
|
-
else {
|
|
2218
|
-
this.outputs.visible = false;
|
|
2219
|
-
}
|
|
2220
|
-
}
|
|
2173
|
+
getLastDistances() {
|
|
2174
|
+
return this.distancesLastMeasure;
|
|
2221
2175
|
}
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
context2d.fill();
|
|
2233
|
-
context2d.beginPath();
|
|
2234
|
-
context2d.strokeStyle = 'orange';
|
|
2235
|
-
context2d.arc(x, y, 240, 0.75 * Math.PI, 0.25 * Math.PI);
|
|
2236
|
-
context2d.lineCap = 'butt';
|
|
2237
|
-
context2d.lineWidth = 80;
|
|
2238
|
-
context2d.stroke();
|
|
2239
|
-
context2d.fillStyle = 'white';
|
|
2240
|
-
context2d.font = '220px Arial';
|
|
2241
|
-
context2d.fillText(`${this.temperature}`, x - 115, y + 75);
|
|
2242
|
-
this.outputs.visible = true;
|
|
2176
|
+
/**
|
|
2177
|
+
* Takes screenshot and saves base64 in lastScreenshotUri
|
|
2178
|
+
* @param sdk Matterport SDK
|
|
2179
|
+
* @returns Promise
|
|
2180
|
+
*/
|
|
2181
|
+
takeScreenShot(sdk) {
|
|
2182
|
+
return sdk.Renderer.takeScreenShot(this.resolution, this.visibility).then((screenShotUri) => {
|
|
2183
|
+
this.lastScreenshotUri = screenShotUri;
|
|
2184
|
+
return Promise.resolve();
|
|
2185
|
+
});
|
|
2243
2186
|
}
|
|
2244
|
-
|
|
2245
|
-
this.
|
|
2246
|
-
if (this.mixer) {
|
|
2247
|
-
this.mixer.update(delta / 1000);
|
|
2248
|
-
}
|
|
2249
|
-
if (this.currentTime > this.nextUpdate) {
|
|
2250
|
-
this.nextUpdate += this.inputs.updateInterval;
|
|
2251
|
-
this.temperature += (Math.random() * this.tempChangeRange);
|
|
2252
|
-
this.temperature = Math.trunc(this.temperature);
|
|
2253
|
-
if (this.temperature > 99) {
|
|
2254
|
-
this.temperature = 99;
|
|
2255
|
-
this.tempChangeRange = -this.tempChangeRange;
|
|
2256
|
-
}
|
|
2257
|
-
if (this.temperature < 10) {
|
|
2258
|
-
this.temperature = 10;
|
|
2259
|
-
this.tempChangeRange = -this.tempChangeRange;
|
|
2260
|
-
}
|
|
2261
|
-
this.component.notify(RepaintEvent);
|
|
2262
|
-
this.cv.repaint();
|
|
2263
|
-
}
|
|
2187
|
+
getScreenShotUri() {
|
|
2188
|
+
return this.lastScreenshotUri;
|
|
2264
2189
|
}
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
this.context = component.context;
|
|
2190
|
+
getLastMeasurement(poseCamera) {
|
|
2191
|
+
return {
|
|
2192
|
+
measure: this.lastMeasure,
|
|
2193
|
+
sweep: poseCamera.sweep,
|
|
2194
|
+
};
|
|
2271
2195
|
}
|
|
2272
|
-
|
|
2273
|
-
this.
|
|
2196
|
+
setLastMeasure(points) {
|
|
2197
|
+
this.lastMeasure = points;
|
|
2198
|
+
}
|
|
2199
|
+
getResolution() {
|
|
2200
|
+
return this.resolution;
|
|
2274
2201
|
}
|
|
2202
|
+
getVisibility() {
|
|
2203
|
+
return this.visibility;
|
|
2204
|
+
}
|
|
2205
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportMeasurementService, deps: [{ token: i1$1.Router }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2206
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportMeasurementService, providedIn: 'root' });
|
|
2275
2207
|
}
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2208
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportMeasurementService, decorators: [{
|
|
2209
|
+
type: Injectable,
|
|
2210
|
+
args: [{
|
|
2211
|
+
providedIn: 'root',
|
|
2212
|
+
}]
|
|
2213
|
+
}], ctorParameters: () => [{ type: i1$1.Router }] });
|
|
2280
2214
|
|
|
2281
|
-
class
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2215
|
+
class MatterportNavigationService {
|
|
2216
|
+
sweepCollection = null;
|
|
2217
|
+
sweeps = null;
|
|
2218
|
+
floors = null;
|
|
2219
|
+
forbiddenSweeps = [];
|
|
2220
|
+
currentSweep = new Subject();
|
|
2221
|
+
onCameraModeChanged = new Subject();
|
|
2222
|
+
/** Emits whenever the set of current rooms changes (sdk.Room.current). */
|
|
2223
|
+
onRoomChanged = new Subject();
|
|
2224
|
+
inTransitionMode = false;
|
|
2225
|
+
inTransitionSweep = false;
|
|
2226
|
+
currentCameraMode = CameraMode.OUTSIDE;
|
|
2227
|
+
currentRooms = [];
|
|
2228
|
+
/** Sequence number of the floor currently visible in sdk.Floor.current (null = single-floor or unknown). */
|
|
2229
|
+
currentFloorSequence = null;
|
|
2230
|
+
constructor() { }
|
|
2231
|
+
async action_toolbox_floorplan(sdk) {
|
|
2232
|
+
if (this.inTransitionMode || this.inTransitionSweep) {
|
|
2233
|
+
console.log('viewer is in transition, cannot go floorplan');
|
|
2234
|
+
return;
|
|
2235
|
+
}
|
|
2236
|
+
try {
|
|
2237
|
+
await sdk.Mode.moveTo('mode.floorplan');
|
|
2238
|
+
}
|
|
2239
|
+
catch (e) {
|
|
2240
|
+
console.log('cannot go to floorplan', e);
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
action_toolbox_inside_view(sdk) {
|
|
2244
|
+
sdk.Mode.moveTo('mode.inside');
|
|
2245
|
+
}
|
|
2246
|
+
actionShowAllFloors(sdk) {
|
|
2247
|
+
try {
|
|
2248
|
+
sdk.Floor.showAll();
|
|
2249
|
+
}
|
|
2250
|
+
catch (e) {
|
|
2251
|
+
console.log('cannot show all floors', e);
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
async action_toolbox_dollhouse(sdk) {
|
|
2255
|
+
setTimeout(async () => {
|
|
2256
|
+
if (this.inTransitionMode || this.inTransitionSweep) {
|
|
2257
|
+
console.log('viewer is in transition, cannot go dollhouse');
|
|
2258
|
+
return;
|
|
2259
|
+
}
|
|
2260
|
+
try {
|
|
2261
|
+
await sdk.Mode.moveTo('mode.dollhouse');
|
|
2262
|
+
}
|
|
2263
|
+
catch (e) {
|
|
2264
|
+
console.log('cannot go to dollhouse', e);
|
|
2265
|
+
}
|
|
2266
|
+
}, 1200);
|
|
2267
|
+
}
|
|
2268
|
+
async action_go_to_floor(sdk, floorName, matterportFloorSequence = null) {
|
|
2269
|
+
if (!this.floors) {
|
|
2270
|
+
console.log('Floor are not loaded yet');
|
|
2271
|
+
return;
|
|
2272
|
+
}
|
|
2273
|
+
let floorMatterport = this.floors.find((floor) => floor.sequence === matterportFloorSequence);
|
|
2274
|
+
if (!floorMatterport) {
|
|
2275
|
+
floorMatterport = this.floors.find((floor) => floorName.includes(floor.name) && floor.name != '');
|
|
2276
|
+
}
|
|
2277
|
+
if (!floorMatterport) {
|
|
2278
|
+
floorMatterport = this.floors.find((floor) => floorName.includes(floor.id));
|
|
2279
|
+
}
|
|
2280
|
+
if (floorMatterport) {
|
|
2281
|
+
let retry = true;
|
|
2282
|
+
while (retry) {
|
|
2283
|
+
try {
|
|
2284
|
+
const floorIndex = await sdk.Floor.moveTo(floorMatterport.sequence);
|
|
2285
|
+
console.debug("moved to floorIndex", floorIndex);
|
|
2286
|
+
retry = false;
|
|
2287
|
+
}
|
|
2288
|
+
catch (error) {
|
|
2289
|
+
console.log('Cannot move to Floor', error);
|
|
2290
|
+
await wait(100);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
else {
|
|
2295
|
+
console.warn('No matterport floor found to move to');
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
async action_go_to_sweep(sdk, sweep, rotation) {
|
|
2299
|
+
if (this.forbiddenSweeps.includes(sweep)) {
|
|
2300
|
+
console.log('user is not allowed to go to this sweep');
|
|
2301
|
+
return;
|
|
2302
|
+
}
|
|
2303
|
+
setTimeout(async () => {
|
|
2304
|
+
try {
|
|
2305
|
+
this.inTransitionSweep = true;
|
|
2306
|
+
await sdk.Sweep.moveTo(sweep, {
|
|
2307
|
+
transition: sdk.Camera.TransitionType.INSTANT,
|
|
2308
|
+
transitionTime: 1500
|
|
2309
|
+
});
|
|
2310
|
+
}
|
|
2311
|
+
catch (error) {
|
|
2312
|
+
this.inTransitionSweep = false;
|
|
2313
|
+
console.log('Cannot move to sweep', error);
|
|
2314
|
+
}
|
|
2315
|
+
if (rotation) {
|
|
2316
|
+
await sdk.Camera.setRotation(rotation, { speed: 100 });
|
|
2317
|
+
}
|
|
2318
|
+
}, 1000);
|
|
2319
|
+
}
|
|
2320
|
+
async removeForbiddenSweeps(sdk, forbiddenSweeps) {
|
|
2321
|
+
this.forbiddenSweeps = [...forbiddenSweeps];
|
|
2322
|
+
let removed = 0;
|
|
2323
|
+
await Promise.all(forbiddenSweeps.map(async (sweep) => {
|
|
2324
|
+
try {
|
|
2325
|
+
await sdk.Sweep.disable(sweep);
|
|
2326
|
+
removed += 1;
|
|
2327
|
+
}
|
|
2328
|
+
catch (error) {
|
|
2329
|
+
console.log(error);
|
|
2330
|
+
}
|
|
2331
|
+
}));
|
|
2332
|
+
console.log('removed sweeps:', removed);
|
|
2333
|
+
}
|
|
2334
|
+
getCurrentSweep(poseCamera) {
|
|
2335
|
+
return poseCamera?.sweep || null;
|
|
2336
|
+
}
|
|
2337
|
+
setCameraMode(mode) {
|
|
2338
|
+
this.inTransitionSweep = false;
|
|
2339
|
+
switch (mode) {
|
|
2340
|
+
case 'mode.dollhouse':
|
|
2341
|
+
this.currentCameraMode = CameraMode.DOLLHOUSE;
|
|
2342
|
+
break;
|
|
2343
|
+
case 'mode.floorplan':
|
|
2344
|
+
this.currentCameraMode = CameraMode.FLOORPLAN;
|
|
2345
|
+
break;
|
|
2346
|
+
case 'mode.inside':
|
|
2347
|
+
this.currentCameraMode = CameraMode.INSIDE;
|
|
2348
|
+
break;
|
|
2349
|
+
case 'mode.transitioning':
|
|
2350
|
+
this.currentCameraMode = CameraMode.TRANSITIONING;
|
|
2351
|
+
break;
|
|
2352
|
+
default:
|
|
2353
|
+
this.currentCameraMode = CameraMode.OUTSIDE;
|
|
2354
|
+
}
|
|
2355
|
+
this.onCameraModeChanged.next(this.currentCameraMode);
|
|
2356
|
+
}
|
|
2357
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportNavigationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2358
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportNavigationService, providedIn: 'root' });
|
|
2359
|
+
}
|
|
2360
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportNavigationService, decorators: [{
|
|
2361
|
+
type: Injectable,
|
|
2362
|
+
args: [{
|
|
2363
|
+
providedIn: 'root',
|
|
2364
|
+
}]
|
|
2365
|
+
}], ctorParameters: () => [] });
|
|
2366
|
+
|
|
2367
|
+
class MatterportPointerService {
|
|
2368
|
+
pointerButton = null;
|
|
2369
|
+
getCursorPositionButton = null;
|
|
2370
|
+
textDisplayCursorPositionPanel = null;
|
|
2371
|
+
cursorPositionButtonDisplayed = false;
|
|
2372
|
+
intervalCursorPointerPosition;
|
|
2373
|
+
timerPointer;
|
|
2374
|
+
oldPoseMatterportPosition;
|
|
2375
|
+
constructor() { }
|
|
2376
|
+
init(container, pointerButton, getCursorPositionButton, textDisplayCursorPositionPanel, callbacks) {
|
|
2377
|
+
this.pointerButton = pointerButton;
|
|
2378
|
+
this.getCursorPositionButton = getCursorPositionButton;
|
|
2379
|
+
this.textDisplayCursorPositionPanel = textDisplayCursorPositionPanel;
|
|
2380
|
+
if (this.pointerButton) {
|
|
2381
|
+
this.pointerButton.addEventListener('click', callbacks.onLeftClick);
|
|
2382
|
+
this.pointerButton.addEventListener('contextmenu', callbacks.onRightClick);
|
|
2383
|
+
}
|
|
2384
|
+
if (this.getCursorPositionButton) {
|
|
2385
|
+
this.getCursorPositionButton.addEventListener('click', callbacks.onMiddleClick);
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
startPointerTrick(sdk, container, getPose, getPoseCamera, getInteractionMode, getMattertagToFollow) {
|
|
2389
|
+
this.timerPointer = setInterval(() => {
|
|
2390
|
+
this.updatePointerTrick(sdk, container, getPose(), getPoseCamera(), getInteractionMode(), getMattertagToFollow());
|
|
2391
|
+
}, 50);
|
|
2392
|
+
}
|
|
2393
|
+
stopPointerTrick() {
|
|
2394
|
+
clearInterval(this.timerPointer);
|
|
2395
|
+
}
|
|
2396
|
+
startAdminCursorTracker(sdk, container, getPose, getPoseCamera) {
|
|
2397
|
+
if (!!this.getCursorPositionButton &&
|
|
2398
|
+
(document.location.href.indexOf('dev') !== -1 || document.location.href.indexOf('localhost') !== -1)) {
|
|
2399
|
+
this.intervalCursorPointerPosition = setInterval(() => {
|
|
2400
|
+
const poseMatterport = getPose();
|
|
2401
|
+
if (!poseMatterport)
|
|
2402
|
+
return;
|
|
2403
|
+
const nextShow = poseMatterport.time + 1000;
|
|
2404
|
+
if (new Date().getTime() > nextShow) {
|
|
2405
|
+
if (this.cursorPositionButtonDisplayed)
|
|
2406
|
+
return;
|
|
2407
|
+
const size = {
|
|
2408
|
+
w: container.clientWidth,
|
|
2409
|
+
h: container.clientHeight,
|
|
2410
|
+
};
|
|
2411
|
+
const coord = sdk.Conversion.worldToScreen(poseMatterport.position, getPoseCamera(), size);
|
|
2412
|
+
this.getCursorPositionButton.style.left = `${coord.x - 25}px`;
|
|
2413
|
+
this.getCursorPositionButton.style.top = `${coord.y - 22}px`;
|
|
2414
|
+
this.getCursorPositionButton.style.display = 'block';
|
|
2415
|
+
this.cursorPositionButtonDisplayed = true;
|
|
2416
|
+
}
|
|
2417
|
+
}, 500);
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
stopAdminCursorTracker() {
|
|
2421
|
+
clearInterval(this.intervalCursorPointerPosition);
|
|
2422
|
+
}
|
|
2423
|
+
updatePointerTrick(sdk, container, poseMatterport, poseCamera, interactionMode, mattertagToFollow) {
|
|
2424
|
+
if (!this.pointerButton)
|
|
2425
|
+
return;
|
|
2426
|
+
if (interactionMode !== 0 && // ViewerInteractions.DEFAULT
|
|
2427
|
+
mattertagToFollow &&
|
|
2428
|
+
poseMatterport &&
|
|
2429
|
+
this.getDistPosition(sdk, container, poseCamera, poseMatterport.position, this.oldPoseMatterportPosition) > 25) {
|
|
2430
|
+
this.pointerButton.style.display = 'none';
|
|
2431
|
+
const size = {
|
|
2432
|
+
w: container.clientWidth,
|
|
2433
|
+
h: container.clientHeight,
|
|
2434
|
+
};
|
|
2435
|
+
const coords = sdk.Conversion.worldToScreen(poseMatterport.position, poseCamera, size);
|
|
2436
|
+
this.pointerButton.style.left = `${coords.x * Math.sign(coords.x) - 25}px`;
|
|
2437
|
+
this.pointerButton.style.top = `${coords.y * Math.sign(coords.x) - 25}px`;
|
|
2438
|
+
this.oldPoseMatterportPosition = {
|
|
2439
|
+
...poseMatterport.position,
|
|
2440
|
+
};
|
|
2441
|
+
}
|
|
2442
|
+
else {
|
|
2443
|
+
this.pointerButton.style.display = 'block';
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
getDistPosition(sdk, container, poseCamera, pos1, pos2) {
|
|
2447
|
+
if (!pos1 || !pos2)
|
|
2448
|
+
return 100; // Force update if one is missing
|
|
2449
|
+
const size = {
|
|
2450
|
+
w: container.clientWidth,
|
|
2451
|
+
h: container.clientHeight,
|
|
2452
|
+
};
|
|
2453
|
+
const coords1 = sdk.Conversion.worldToScreen(pos1, poseCamera, size);
|
|
2454
|
+
const coords2 = sdk.Conversion.worldToScreen(pos2, poseCamera, size);
|
|
2455
|
+
return Math.sqrt((coords1.x - coords2.x) ** 2 + (coords1.y - coords2.y) ** 2);
|
|
2456
|
+
}
|
|
2457
|
+
updateCursorDisplay(poseMatterport) {
|
|
2458
|
+
if (this.textDisplayCursorPositionPanel && poseMatterport) {
|
|
2459
|
+
this.textDisplayCursorPositionPanel.innerHTML = `position:
|
|
2460
|
+
${pointToString(poseMatterport.position)}\n
|
|
2461
|
+
normal:
|
|
2462
|
+
${pointToString(poseMatterport.normal)}\n
|
|
2463
|
+
floorId:
|
|
2464
|
+
${poseMatterport.floorId}`;
|
|
2465
|
+
if (this.getCursorPositionButton) {
|
|
2466
|
+
this.getCursorPositionButton.style.display = 'none';
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
clear(callbacks) {
|
|
2471
|
+
if (this.pointerButton) {
|
|
2472
|
+
this.pointerButton.removeEventListener('click', callbacks.onLeftClick);
|
|
2473
|
+
this.pointerButton.removeEventListener('contextmenu', callbacks.onRightClick);
|
|
2474
|
+
}
|
|
2475
|
+
if (this.getCursorPositionButton) {
|
|
2476
|
+
this.getCursorPositionButton.removeEventListener('click', callbacks.onMiddleClick);
|
|
2477
|
+
}
|
|
2478
|
+
this.stopPointerTrick();
|
|
2479
|
+
this.stopAdminCursorTracker();
|
|
2480
|
+
}
|
|
2481
|
+
setCursorPositionButtonDisplayed(value) {
|
|
2482
|
+
this.cursorPositionButtonDisplayed = value;
|
|
2483
|
+
}
|
|
2484
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportPointerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2485
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportPointerService, providedIn: 'root' });
|
|
2486
|
+
}
|
|
2487
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportPointerService, decorators: [{
|
|
2488
|
+
type: Injectable,
|
|
2489
|
+
args: [{
|
|
2490
|
+
providedIn: 'root',
|
|
2491
|
+
}]
|
|
2492
|
+
}], ctorParameters: () => [] });
|
|
2493
|
+
|
|
2494
|
+
const HoverEvent$1 = 'hover';
|
|
2495
|
+
const UnhoverEvent$1 = 'unhover';
|
|
2496
|
+
const RepaintEvent = 'repaint';
|
|
2497
|
+
class NestThermostat extends SceneComponent {
|
|
2498
|
+
cv = null;
|
|
2499
|
+
planeRenderer = null;
|
|
2500
|
+
rootScene = null;
|
|
2501
|
+
mixer = null;
|
|
2502
|
+
onEnterClip = null;
|
|
2503
|
+
mesh = null;
|
|
2504
|
+
currentTime = 0;
|
|
2505
|
+
nextUpdate = 0;
|
|
2506
|
+
temperature = 0;
|
|
2507
|
+
tempChangeRange = 5;
|
|
2508
|
+
component;
|
|
2509
|
+
inputs = {
|
|
2510
|
+
loadingState: 'Idle',
|
|
2511
|
+
texture: null,
|
|
2512
|
+
updateInterval: 1000,
|
|
2513
|
+
};
|
|
2514
|
+
outputs = {
|
|
2515
|
+
painter: null,
|
|
2516
|
+
visible: false,
|
|
2296
2517
|
};
|
|
2297
2518
|
events = {
|
|
2298
|
-
[
|
|
2519
|
+
[HoverEvent$1]: true,
|
|
2520
|
+
[UnhoverEvent$1]: true,
|
|
2299
2521
|
};
|
|
2300
|
-
onInit(modelNode, inputTexture) {
|
|
2301
|
-
this.inputs.texture = inputTexture;
|
|
2522
|
+
onInit(modelNode, plane, inputTexture) {
|
|
2302
2523
|
if (!this.context) {
|
|
2303
2524
|
this.context = {
|
|
2304
2525
|
root: modelNode
|
|
2305
2526
|
};
|
|
2306
2527
|
}
|
|
2307
|
-
this.
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
this.
|
|
2318
|
-
this.
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
this.notify(eventType, eventData);
|
|
2528
|
+
this.inputs.texture = inputTexture;
|
|
2529
|
+
const root = this.context.root;
|
|
2530
|
+
const THREE = this.context.three;
|
|
2531
|
+
this.planeRenderer = plane;
|
|
2532
|
+
this.planeRenderer.outputs.objectRoot.translateZ(0.05);
|
|
2533
|
+
this.planeRenderer.outputs.objectRoot.translateY(0.4);
|
|
2534
|
+
this.planeRenderer.outputs.objectRoot.scale.set(0.5, 0.5, 0.5);
|
|
2535
|
+
// planeRenderer.inputs.localPosition.z = 0.05;
|
|
2536
|
+
// planeRenderer.inputs.localPosition.y = 0.4;
|
|
2537
|
+
// planeRenderer.inputs.localScale = {x: 0.5, y: 0.5, z: 0.5};
|
|
2538
|
+
this.outputs.painter = this;
|
|
2539
|
+
this.mixer = new AnimationMixer(this.planeRenderer.outputs.objectRoot);
|
|
2540
|
+
const tm = 0.2;
|
|
2541
|
+
const positionTrack = new VectorKeyframeTrack('.scale', [0, tm], [
|
|
2542
|
+
0, 0, 0,
|
|
2543
|
+
0.5, 0.5, 0.5
|
|
2544
|
+
], InterpolateSmooth);
|
|
2545
|
+
this.onEnterClip = new AnimationClip(null, tm, [positionTrack]);
|
|
2326
2546
|
}
|
|
2327
|
-
onInputsUpdated(
|
|
2328
|
-
if (
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2547
|
+
onInputsUpdated() {
|
|
2548
|
+
if (this.inputs.loadingState === 'Loaded') {
|
|
2549
|
+
const lines = [];
|
|
2550
|
+
//@ts-ignore
|
|
2551
|
+
this.context.root.obj3D.traverse((obj) => {
|
|
2552
|
+
// we dont want line segments, track them and remove them.
|
|
2553
|
+
if (obj.type === 'LineSegments') {
|
|
2554
|
+
lines.push(obj);
|
|
2555
|
+
}
|
|
2556
|
+
else if (obj.type === 'Mesh') {
|
|
2557
|
+
this.mesh = obj;
|
|
2558
|
+
const materials = this.mesh.material;
|
|
2559
|
+
materials.forEach((m, idx) => {
|
|
2560
|
+
if (m && m.map.source.data.outerHTML.indexOf('_5b76dbe388862300126c1e14') !== -1) {
|
|
2561
|
+
const newMaterial = new MeshBasicMaterial({ map: this.inputs.texture });
|
|
2562
|
+
this.mesh.material[idx] = newMaterial;
|
|
2563
|
+
}
|
|
2564
|
+
});
|
|
2565
|
+
}
|
|
2566
|
+
});
|
|
2567
|
+
// remove the line segments.
|
|
2568
|
+
lines.forEach((line) => {
|
|
2569
|
+
line.parent.remove(line);
|
|
2570
|
+
});
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
onEvent(eventType, eventData) {
|
|
2574
|
+
if (eventType === HoverEvent$1) {
|
|
2575
|
+
const data = eventData;
|
|
2576
|
+
if (data.hover) {
|
|
2577
|
+
this.outputs.visible = true;
|
|
2578
|
+
const onEnterAction = this.mixer.clipAction(this.onEnterClip);
|
|
2579
|
+
onEnterAction.stop();
|
|
2580
|
+
onEnterAction.loop = LoopOnce;
|
|
2581
|
+
onEnterAction.clampWhenFinished = true;
|
|
2582
|
+
onEnterAction.play();
|
|
2583
|
+
}
|
|
2584
|
+
else {
|
|
2585
|
+
this.outputs.visible = false;
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
paint(context2d, size) {
|
|
2590
|
+
const x = 490;
|
|
2591
|
+
const y = 490;
|
|
2592
|
+
context2d.fillStyle = 'black';
|
|
2593
|
+
context2d.beginPath();
|
|
2594
|
+
context2d.arc(x, y, 400, 0, Math.PI * 2);
|
|
2595
|
+
context2d.fill();
|
|
2596
|
+
context2d.fillStyle = '#CF5300';
|
|
2597
|
+
context2d.beginPath();
|
|
2598
|
+
context2d.arc(x, y, 300, 0, Math.PI * 2);
|
|
2599
|
+
context2d.fill();
|
|
2600
|
+
context2d.beginPath();
|
|
2601
|
+
context2d.strokeStyle = 'orange';
|
|
2602
|
+
context2d.arc(x, y, 240, 0.75 * Math.PI, 0.25 * Math.PI);
|
|
2603
|
+
context2d.lineCap = 'butt';
|
|
2604
|
+
context2d.lineWidth = 80;
|
|
2605
|
+
context2d.stroke();
|
|
2606
|
+
context2d.fillStyle = 'white';
|
|
2607
|
+
context2d.font = '220px Arial';
|
|
2608
|
+
context2d.fillText(`${this.temperature}`, x - 115, y + 75);
|
|
2609
|
+
this.outputs.visible = true;
|
|
2610
|
+
}
|
|
2611
|
+
onTick(delta) {
|
|
2612
|
+
this.currentTime += delta;
|
|
2613
|
+
if (this.mixer) {
|
|
2614
|
+
this.mixer.update(delta / 1000);
|
|
2615
|
+
}
|
|
2616
|
+
if (this.currentTime > this.nextUpdate) {
|
|
2617
|
+
this.nextUpdate += this.inputs.updateInterval;
|
|
2618
|
+
this.temperature += (Math.random() * this.tempChangeRange);
|
|
2619
|
+
this.temperature = Math.trunc(this.temperature);
|
|
2620
|
+
if (this.temperature > 99) {
|
|
2621
|
+
this.temperature = 99;
|
|
2622
|
+
this.tempChangeRange = -this.tempChangeRange;
|
|
2623
|
+
}
|
|
2624
|
+
if (this.temperature < 10) {
|
|
2625
|
+
this.temperature = 10;
|
|
2626
|
+
this.tempChangeRange = -this.tempChangeRange;
|
|
2627
|
+
}
|
|
2628
|
+
this.component.notify(RepaintEvent);
|
|
2629
|
+
this.cv.repaint();
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
setComponent(component, plane, cv) {
|
|
2633
|
+
component.onTick = this.onTick.bind(this);
|
|
2634
|
+
// plane.onTick = this.onTick.bind(this);
|
|
2635
|
+
this.cv = cv;
|
|
2636
|
+
this.component = component;
|
|
2637
|
+
this.context = component.context;
|
|
2638
|
+
}
|
|
2639
|
+
setRootScene(rootScene) {
|
|
2640
|
+
this.rootScene = rootScene;
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
const nestThermostatType = 'mp.nestThermostat';
|
|
2644
|
+
const makeNestThermostat = function () {
|
|
2645
|
+
return new NestThermostat();
|
|
2646
|
+
};
|
|
2647
|
+
|
|
2648
|
+
class PlaneRenderer extends SceneComponent {
|
|
2649
|
+
rootScene = null;
|
|
2650
|
+
mesh;
|
|
2651
|
+
pivotNode;
|
|
2652
|
+
inputs = {
|
|
2653
|
+
texture: null,
|
|
2654
|
+
aspect: 1,
|
|
2655
|
+
transparent: true,
|
|
2656
|
+
visible: true,
|
|
2657
|
+
opacity: 1,
|
|
2658
|
+
polygonOffset: false,
|
|
2659
|
+
polygonOffsetFactor: 0,
|
|
2660
|
+
polygonOffsetUnits: 0,
|
|
2661
|
+
localScale: { x: 1, y: 1, z: 1 },
|
|
2662
|
+
localPosition: { x: 0, y: 0, z: 0 },
|
|
2663
|
+
};
|
|
2664
|
+
events = {
|
|
2665
|
+
[ComponentInteractionType.CLICK]: true,
|
|
2666
|
+
};
|
|
2667
|
+
onInit(modelNode, inputTexture) {
|
|
2668
|
+
this.inputs.texture = inputTexture;
|
|
2669
|
+
if (!this.context) {
|
|
2670
|
+
this.context = {
|
|
2671
|
+
root: modelNode
|
|
2672
|
+
};
|
|
2673
|
+
}
|
|
2674
|
+
this.pivotNode = new Group();
|
|
2675
|
+
this.mesh = new Mesh(new PlaneBufferGeometry(1.0, 1.0), new MeshBasicMaterial({
|
|
2676
|
+
transparent: this.inputs.transparent,
|
|
2677
|
+
map: this.inputs.texture,
|
|
2678
|
+
opacity: this.inputs.opacity,
|
|
2679
|
+
polygonOffset: this.inputs.polygonOffset,
|
|
2680
|
+
polygonOffsetFactor: this.inputs.polygonOffsetFactor,
|
|
2681
|
+
polygonOffsetUnits: this.inputs.polygonOffsetUnits,
|
|
2682
|
+
}));
|
|
2683
|
+
this.mesh.scale.set(this.inputs.localScale.x, this.inputs.localScale.y / this.inputs.aspect, this.inputs.localScale.z);
|
|
2684
|
+
this.mesh.position.set(this.inputs.localPosition.x, this.inputs.localPosition.y, this.inputs.localPosition.z);
|
|
2685
|
+
this.mesh.updateMatrixWorld();
|
|
2686
|
+
this.pivotNode.add(this.mesh);
|
|
2687
|
+
this.outputs.objectRoot = this.pivotNode;
|
|
2688
|
+
this.outputs.collider = this.pivotNode;
|
|
2689
|
+
this.mesh.visible = this.inputs.visible;
|
|
2690
|
+
}
|
|
2691
|
+
onEvent(eventType, eventData) {
|
|
2692
|
+
this.notify(eventType, eventData);
|
|
2693
|
+
}
|
|
2694
|
+
onInputsUpdated(oldInputs) {
|
|
2695
|
+
if (oldInputs.transparent !== this.inputs.transparent) {
|
|
2696
|
+
this.mesh.material.transparent = this.inputs.transparent;
|
|
2697
|
+
}
|
|
2698
|
+
if (oldInputs.texture !== this.inputs.texture) {
|
|
2699
|
+
const material = this.mesh.material;
|
|
2700
|
+
material.map = this.inputs.texture;
|
|
2701
|
+
material.needsUpdate = true;
|
|
2702
|
+
}
|
|
2703
|
+
if (oldInputs.visible !== this.inputs.visible) {
|
|
2704
|
+
this.mesh.visible = this.inputs.visible;
|
|
2705
|
+
}
|
|
2706
|
+
if (oldInputs.polygonOffset !== this.inputs.polygonOffset) {
|
|
2707
|
+
const material = this.mesh.material;
|
|
2708
|
+
material.polygonOffset = this.inputs.polygonOffset;
|
|
2709
|
+
material.polygonOffsetFactor = this.inputs.polygonOffsetFactor;
|
|
2710
|
+
material.polygonOffsetUnits = this.inputs.polygonOffsetUnits;
|
|
2711
|
+
}
|
|
2712
|
+
this.mesh.scale.set(this.inputs.localScale.x, this.inputs.localScale.y / this.inputs.aspect, this.inputs.localScale.z);
|
|
2713
|
+
this.mesh.position.set(this.inputs.localPosition.x, this.inputs.localPosition.y, this.inputs.localPosition.z);
|
|
2714
|
+
}
|
|
2715
|
+
onDestroy() {
|
|
2716
|
+
this.outputs.collider = null;
|
|
2717
|
+
this.outputs.objectRoot = null;
|
|
2718
|
+
this.mesh.material.dispose();
|
|
2719
|
+
this.mesh.geometry.dispose();
|
|
2720
|
+
}
|
|
2721
|
+
setRootScene(rootScene) {
|
|
2722
|
+
this.rootScene = rootScene;
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
const planeRendererType = 'mp.planeRenderer';
|
|
2726
|
+
function makePlaneRenderer() {
|
|
2727
|
+
return new PlaneRenderer();
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
class CanvasRenderer extends SceneComponent {
|
|
2731
|
+
canvas;
|
|
2732
|
+
renderContext2D;
|
|
2733
|
+
inputs = {
|
|
2734
|
+
painter: null,
|
|
2735
|
+
textureRes: { w: 1024, h: 1024 }, // dim for thermostat
|
|
2736
|
+
};
|
|
2737
|
+
outputs = {
|
|
2738
|
+
texture: null,
|
|
2739
|
+
};
|
|
2740
|
+
events = {
|
|
2741
|
+
repaint: true,
|
|
2742
|
+
};
|
|
2743
|
+
onInit() {
|
|
2744
|
+
// set up canvas 2d context
|
|
2745
|
+
this.canvas = document.createElement('canvas');
|
|
2746
|
+
this.renderContext2D = this.canvas.getContext('2d');
|
|
2747
|
+
this.outputs.texture = new CanvasTexture(this.canvas);
|
|
2748
|
+
this.resize(this.inputs.textureRes);
|
|
2749
|
+
this.repaint();
|
|
2750
|
+
}
|
|
2751
|
+
setCanvasNestThermostatPainter(sc) {
|
|
2752
|
+
this.inputs.painter = sc;
|
|
2753
|
+
}
|
|
2754
|
+
onInputsUpdated(oldInputs) {
|
|
2755
|
+
if (oldInputs.textureRes.w !== this.inputs.textureRes.w ||
|
|
2756
|
+
oldInputs.textureRes.h !== this.inputs.textureRes.h) {
|
|
2757
|
+
this.resize(this.inputs.textureRes);
|
|
2758
|
+
}
|
|
2759
|
+
if (oldInputs.painter !== this.inputs.painter) {
|
|
2760
|
+
this.repaint();
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
onEvent(eventType, _eventData) {
|
|
2764
|
+
if (eventType === 'repaint') {
|
|
2765
|
+
this.repaint();
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
onDestroy() {
|
|
2769
|
+
this.outputs.texture.dispose();
|
|
2770
|
+
this.outputs.texture = null;
|
|
2771
|
+
}
|
|
2772
|
+
resize(size) {
|
|
2773
|
+
this.canvas.width = size.w;
|
|
2774
|
+
this.canvas.height = size.h;
|
|
2775
|
+
}
|
|
2776
|
+
repaint() {
|
|
2777
|
+
if (this.inputs.painter) {
|
|
2778
|
+
this.inputs.painter.paint(this.renderContext2D, this.inputs.textureRes);
|
|
2779
|
+
this.outputs.texture.needsUpdate = true;
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
const canvasRendererType = 'mp.canvasRenderer';
|
|
2784
|
+
function makeCanvasRenderer() {
|
|
2785
|
+
return new CanvasRenderer();
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
const HoverEvent = 'hover';
|
|
2789
|
+
const UnhoverEvent = 'unhover';
|
|
2790
|
+
class TvPlayer extends SceneComponent {
|
|
2791
|
+
rootScene = null;
|
|
2792
|
+
mesh = null;
|
|
2793
|
+
component;
|
|
2794
|
+
inputs = {
|
|
2795
|
+
loadingState: 'Idle',
|
|
2796
|
+
texture: null,
|
|
2797
|
+
updateInterval: 1000,
|
|
2798
|
+
};
|
|
2799
|
+
events = {
|
|
2800
|
+
[HoverEvent]: true,
|
|
2801
|
+
[UnhoverEvent]: true,
|
|
2802
|
+
};
|
|
2803
|
+
intervalVideoTexture;
|
|
2804
|
+
onInit(modelNode) {
|
|
2805
|
+
if (!this.context) {
|
|
2806
|
+
this.context = {
|
|
2807
|
+
root: modelNode
|
|
2808
|
+
};
|
|
2809
|
+
}
|
|
2810
|
+
const root = this.context.root;
|
|
2811
|
+
const THREE = this.context.three;
|
|
2812
|
+
}
|
|
2813
|
+
onDestroy() {
|
|
2814
|
+
super.onDestroy();
|
|
2815
|
+
clearInterval(this.intervalVideoTexture);
|
|
2816
|
+
}
|
|
2817
|
+
onInputsUpdated() {
|
|
2818
|
+
if (this.inputs.loadingState === 'Loaded') {
|
|
2819
|
+
const lines = [];
|
|
2820
|
+
//@ts-ignore
|
|
2821
|
+
this.context.root.obj3D.traverse((obj) => {
|
|
2822
|
+
// we dont want line segments, track them and remove them.
|
|
2823
|
+
if (obj.type === 'LineSegments') {
|
|
2824
|
+
lines.push(obj);
|
|
2825
|
+
}
|
|
2826
|
+
else if (obj.type === 'Mesh') {
|
|
2827
|
+
this.mesh = obj;
|
|
2828
|
+
let video, videoImage, videoImageContext, videoTexture;
|
|
2829
|
+
// create the video element
|
|
2830
|
+
video = document.createElement('video');
|
|
2831
|
+
// video.src = "./../assets/video/video_samsic.mp4";
|
|
2832
|
+
video.src = "./../assets/video/121222-04.mp4";
|
|
2833
|
+
video.load(); // must call after setting/changing source
|
|
2834
|
+
video.loop = true;
|
|
2835
|
+
video.play();
|
|
2836
|
+
videoImage = document.createElement('canvas');
|
|
2837
|
+
// videoImage.width = 640;
|
|
2838
|
+
videoImage.width = 1280;
|
|
2839
|
+
// videoImage.height = 360;
|
|
2840
|
+
videoImage.height = 720;
|
|
2841
|
+
videoImageContext = videoImage.getContext('2d');
|
|
2842
|
+
// background color if no video present
|
|
2843
|
+
videoImageContext.fillStyle = '#000000';
|
|
2844
|
+
videoImageContext.fillRect(0, 0, videoImage.width, videoImage.height);
|
|
2845
|
+
videoTexture = new Texture(videoImage);
|
|
2846
|
+
videoTexture.minFilter = LinearFilter;
|
|
2847
|
+
videoTexture.magFilter = LinearFilter;
|
|
2848
|
+
const movieMaterial = new MeshBasicMaterial({ map: videoTexture });
|
|
2849
|
+
this.mesh.material = movieMaterial;
|
|
2850
|
+
const render = () => {
|
|
2851
|
+
if (video.readyState === video.HAVE_ENOUGH_DATA) {
|
|
2852
|
+
videoImageContext.drawImage(video, 0, 0);
|
|
2853
|
+
if (videoTexture)
|
|
2854
|
+
videoTexture.needsUpdate = true;
|
|
2855
|
+
}
|
|
2856
|
+
const camera = (this.context.scene.children.find(u => u.constructor.name === 'CameraRig')).camera;
|
|
2857
|
+
this.context.renderer.render(this.context.scene, camera);
|
|
2858
|
+
};
|
|
2859
|
+
this.intervalVideoTexture = setInterval(() => {
|
|
2860
|
+
render();
|
|
2861
|
+
}, 180);
|
|
2862
|
+
}
|
|
2863
|
+
});
|
|
2864
|
+
// remove the line segments.
|
|
2865
|
+
lines.forEach((line) => {
|
|
2866
|
+
line.parent.remove(line);
|
|
2867
|
+
});
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
setComponent(component) {
|
|
2871
|
+
this.component = component;
|
|
2872
|
+
this.context = component.context;
|
|
2873
|
+
}
|
|
2874
|
+
setRootScene(rootScene) {
|
|
2875
|
+
this.rootScene = rootScene;
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
const TvPlayerType = 'mp.TvPlayer';
|
|
2879
|
+
const makeTvPlayer = function () {
|
|
2880
|
+
return new TvPlayer();
|
|
2881
|
+
};
|
|
2882
|
+
|
|
2883
|
+
class MatterportObject3DService {
|
|
2884
|
+
dictionnaryObjects3D = new Map();
|
|
2885
|
+
dictionnarySceneObjects3D = new Map();
|
|
2886
|
+
lastObject3D; // Three JS object
|
|
2887
|
+
objectControl;
|
|
2888
|
+
securityCameraAnimator;
|
|
2889
|
+
azimuthalCrown;
|
|
2890
|
+
threeJSScene;
|
|
2891
|
+
noLightForObjects = true;
|
|
2892
|
+
constructor() { }
|
|
2893
|
+
async init3DObjectViewer(sdk) {
|
|
2894
|
+
const [sceneObject] = await sdk.Scene.createObjects(1);
|
|
2895
|
+
const node = sceneObject.addNode();
|
|
2896
|
+
node.start();
|
|
2897
|
+
this.threeJSScene = node.obj3D.parent;
|
|
2898
|
+
const nodeControl = sceneObject.addNode();
|
|
2899
|
+
this.objectControl = nodeControl.addComponent('mp.transformControls');
|
|
2900
|
+
nodeControl.start();
|
|
2901
|
+
}
|
|
2902
|
+
async add3DObject(sdk, obj, mode) {
|
|
2903
|
+
return new Promise(async (resolve) => {
|
|
2904
|
+
const [sceneObject] = await sdk.Scene.createObjects(1);
|
|
2905
|
+
let isAnimatedSecurityCamera = (obj.object === "security_camera");
|
|
2906
|
+
let isNestThermostat = (obj.object === "nest_thermostat");
|
|
2907
|
+
let isSmarterplanPromotionalVideo = (obj.object === 'video');
|
|
2908
|
+
let isAzimuthalCrown = (obj.object === 'azimuth');
|
|
2909
|
+
const modelNode = sceneObject.addNode();
|
|
2910
|
+
let component = null;
|
|
2911
|
+
const initial = {
|
|
2912
|
+
url: `/assets/3Dobjects/objects/${obj.object}${obj.format.indexOf('.') === -1 ? '.' + obj.format : obj.format}`,
|
|
2913
|
+
localRotation: { "x": 0, "y": 0, "z": 0 },
|
|
2914
|
+
localPosition: { "x": 0, "y": 0, "z": 0 },
|
|
2915
|
+
visible: true,
|
|
2916
|
+
colliderEnabled: true
|
|
2917
|
+
};
|
|
2918
|
+
switch (obj.format) {
|
|
2919
|
+
case '.obj':
|
|
2920
|
+
case 'obj':
|
|
2921
|
+
component = modelNode.addComponent('mp.objLoader', initial);
|
|
2922
|
+
break;
|
|
2923
|
+
case '.fbx':
|
|
2924
|
+
case 'fbx':
|
|
2925
|
+
component = modelNode.addComponent('mp.fbxLoader', initial);
|
|
2926
|
+
break;
|
|
2927
|
+
case '.gltf':
|
|
2928
|
+
case 'gltf':
|
|
2929
|
+
case '.glb':
|
|
2930
|
+
case 'glb':
|
|
2931
|
+
component = modelNode.addComponent('mp.gltfLoader', initial);
|
|
2932
|
+
break;
|
|
2933
|
+
case '.dae':
|
|
2934
|
+
case 'dae':
|
|
2935
|
+
component = modelNode.addComponent('mp.daeLoader', initial);
|
|
2936
|
+
break;
|
|
2937
|
+
default:
|
|
2938
|
+
console.log('Format not supported');
|
|
2939
|
+
break;
|
|
2940
|
+
}
|
|
2941
|
+
if (this.noLightForObjects) {
|
|
2942
|
+
const lightsNode = sceneObject.addNode();
|
|
2943
|
+
lightsNode.addComponent('mp.ambientLight', {
|
|
2944
|
+
intensity: 1,
|
|
2945
|
+
color: { r: 1.0, g: 1.0, b: 1.0 },
|
|
2946
|
+
});
|
|
2947
|
+
this.noLightForObjects = false;
|
|
2948
|
+
}
|
|
2949
|
+
modelNode.obj3D.position.set(obj.position.x, obj.position.y, obj.position.z);
|
|
2950
|
+
modelNode.obj3D.rotation.set(obj.rotation.x, obj.rotation.y, obj.rotation.z);
|
|
2951
|
+
modelNode.obj3D.scale.set(obj.scale.x, obj.scale.y, obj.scale.z);
|
|
2952
|
+
if (isAzimuthalCrown) {
|
|
2953
|
+
this.azimuthalCrown = modelNode;
|
|
2954
|
+
}
|
|
2955
|
+
if (mode && !isNestThermostat) {
|
|
2956
|
+
this.attachGizmoControlTo3DObject(sdk, modelNode, sceneObject, mode, true, true).catch((e) => console.log(e));
|
|
2957
|
+
}
|
|
2958
|
+
if (this.lastObject3D && typeof this.lastObject3D.id === 'string') {
|
|
2959
|
+
modelNode.obj3D.uuid = this.lastObject3D.id;
|
|
2960
|
+
}
|
|
2961
|
+
else if (obj.id) {
|
|
2962
|
+
modelNode.obj3D.uuid = obj.id;
|
|
2963
|
+
}
|
|
2964
|
+
this.lastObject3D = modelNode.obj3D;
|
|
2965
|
+
this.dictionnaryObjects3D.set(modelNode.obj3D.uuid, modelNode);
|
|
2966
|
+
this.dictionnarySceneObjects3D.set(modelNode.obj3D.uuid, sceneObject);
|
|
2967
|
+
if (isAnimatedSecurityCamera) {
|
|
2968
|
+
const animator = modelNode.addComponent('mp.securityCamera', {
|
|
2969
|
+
"nearPlane": 0.1, "farPlane": 10, "horizontalFOV": 52, "aspect": 1.7777777777777777,
|
|
2970
|
+
"localPosition": { "x": 0.3, "y": 0.18, "z": 0 },
|
|
2971
|
+
"localRotation": { "x": -15, "y": -90, "z": 0 },
|
|
2972
|
+
"color": 65280, "panPeriod": 5, "panAngle": -45
|
|
2973
|
+
});
|
|
2974
|
+
this.securityCameraAnimator = animator;
|
|
2975
|
+
if (!obj.viewFrustum) {
|
|
2976
|
+
setTimeout(() => { animator.toggleViewFrustum(); }, 1000);
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
if (isNestThermostat) {
|
|
2980
|
+
const cv = new CanvasRenderer();
|
|
2981
|
+
cv.onInit();
|
|
2982
|
+
const plane = new PlaneRenderer();
|
|
2983
|
+
plane.outputs = { objectRoot: new Object3D(), collider: new Object3D() };
|
|
2984
|
+
const inputTexture = cv.outputs.texture;
|
|
2985
|
+
plane.setRootScene(this.threeJSScene);
|
|
2986
|
+
plane.onInit(modelNode, inputTexture);
|
|
2987
|
+
const sc = new NestThermostat();
|
|
2988
|
+
sc.setComponent(component, plane, cv);
|
|
2989
|
+
sc.setRootScene(this.threeJSScene);
|
|
2990
|
+
sc.onInit(modelNode, plane, inputTexture);
|
|
2991
|
+
cv.setCanvasNestThermostatPainter(sc);
|
|
2992
|
+
setTimeout(() => { sc.inputs.loadingState = "Loaded"; sc.onInputsUpdated(); }, 5000);
|
|
2993
|
+
}
|
|
2994
|
+
if (isSmarterplanPromotionalVideo) {
|
|
2995
|
+
const sc = new TvPlayer();
|
|
2996
|
+
sc.setComponent(component);
|
|
2997
|
+
sc.onInit(modelNode);
|
|
2998
|
+
setTimeout(() => { sc.inputs.loadingState = "Loaded"; sc.onInputsUpdated(); }, 5000);
|
|
2999
|
+
}
|
|
3000
|
+
sceneObject.start();
|
|
3001
|
+
resolve(this.lastObject3D);
|
|
3002
|
+
});
|
|
3003
|
+
}
|
|
3004
|
+
async deleteObject3D(uuid) {
|
|
3005
|
+
const obj = this.dictionnaryObjects3D.get(uuid);
|
|
3006
|
+
if (obj)
|
|
3007
|
+
obj.obj3D.visible = false;
|
|
3008
|
+
}
|
|
3009
|
+
getObject3DModelNodeFromDictionnary(uuid) {
|
|
3010
|
+
let obj = this.dictionnaryObjects3D.get(uuid);
|
|
3011
|
+
if (!obj)
|
|
3012
|
+
return null;
|
|
3013
|
+
if (obj.obj3D.uuid != uuid) {
|
|
3014
|
+
obj.obj3D.uuid = uuid;
|
|
3015
|
+
}
|
|
3016
|
+
return obj;
|
|
3017
|
+
}
|
|
3018
|
+
toggleObjectVisibility(objectId) {
|
|
3019
|
+
let obj = this.dictionnaryObjects3D.get(objectId);
|
|
3020
|
+
if (obj)
|
|
3021
|
+
obj.obj3D.visible = !obj.obj3D.visible;
|
|
3022
|
+
}
|
|
3023
|
+
isObjectVisible(objectId) {
|
|
3024
|
+
let obj = this.dictionnaryObjects3D.get(objectId);
|
|
3025
|
+
return obj ? obj.obj3D.visible : false;
|
|
3026
|
+
}
|
|
3027
|
+
async pointCameraTo3DObject(sdk, objectId, createTagCallback, goToTagCallback, deleteLastTagCallback, getTagFromElementId) {
|
|
3028
|
+
let obj = this.dictionnaryObjects3D.get(objectId);
|
|
3029
|
+
const poiObject = {
|
|
3030
|
+
coordinate: JSON.stringify(obj.obj3D.position),
|
|
3031
|
+
type: PoiType.OBJECT3D,
|
|
3032
|
+
elementID: objectId,
|
|
3033
|
+
};
|
|
3034
|
+
const objectDb = { id: objectId };
|
|
3035
|
+
try {
|
|
3036
|
+
await createTagCallback(PoiType.OBJECT3D, objectDb, poiObject);
|
|
3037
|
+
}
|
|
3038
|
+
catch (err) { }
|
|
3039
|
+
let result = getTagFromElementId(objectId);
|
|
3040
|
+
await goToTagCallback(result.tag);
|
|
3041
|
+
deleteLastTagCallback();
|
|
3042
|
+
}
|
|
3043
|
+
getSceneNodeFromObject3DId(uuid) {
|
|
3044
|
+
return this.dictionnarySceneObjects3D.get(uuid);
|
|
3045
|
+
}
|
|
3046
|
+
async displayAzimutalCrown(poseCamera) {
|
|
3047
|
+
if (this.azimuthalCrown && poseCamera) {
|
|
3048
|
+
this.azimuthalCrown.obj3D.position.set(poseCamera.position.x, poseCamera.position.y, poseCamera.position.z);
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
async attachGizmoControlTo3DObject(sdk, modelNode, sceneObject, mode, visible, isNewObject) {
|
|
3052
|
+
let node = sceneObject.addNode();
|
|
3053
|
+
if (!node) {
|
|
3054
|
+
const [newSceneObject] = await sdk.Scene.createObjects(1);
|
|
3055
|
+
node = newSceneObject.addNode();
|
|
3056
|
+
}
|
|
3057
|
+
const myControl = node.addComponent('mp.transformControls');
|
|
3058
|
+
node.start();
|
|
3059
|
+
myControl.transformControls.visible = visible;
|
|
3060
|
+
myControl.inputs.selection = modelNode;
|
|
3061
|
+
myControl.inputs.mode = mode;
|
|
3062
|
+
modelNode.obj3D.controls = myControl;
|
|
3063
|
+
if (isNewObject) {
|
|
3064
|
+
if (!this.lastObject3D || !this.lastObject3D.controls) {
|
|
3065
|
+
try {
|
|
3066
|
+
modelNode.obj3D.uuid = this.lastObject3D.uuid || this.lastObject3D.id;
|
|
3067
|
+
}
|
|
3068
|
+
catch (e) {
|
|
3069
|
+
console.log(`id obj in Scene was not assigned to id from DB`);
|
|
3070
|
+
}
|
|
3071
|
+
this.lastObject3D = modelNode.obj3D;
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
else {
|
|
3075
|
+
this.lastObject3D = modelNode.obj3D;
|
|
3076
|
+
}
|
|
3077
|
+
return modelNode;
|
|
3078
|
+
}
|
|
3079
|
+
removeGizmoFromLastObject() {
|
|
3080
|
+
if (this.lastObject3D && this.lastObject3D.controls) {
|
|
3081
|
+
this.lastObject3D.controls.transformControls.visible = false;
|
|
3082
|
+
this.lastObject3D.controls.transformControls.dispose();
|
|
3083
|
+
this.lastObject3D.controls = null;
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
toggleViewFrustum() {
|
|
3087
|
+
if (this.securityCameraAnimator) {
|
|
3088
|
+
this.securityCameraAnimator.toggleViewFrustum();
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
clear() {
|
|
3092
|
+
this.dictionnaryObjects3D.clear();
|
|
3093
|
+
this.dictionnarySceneObjects3D.clear();
|
|
3094
|
+
this.lastObject3D = null;
|
|
3095
|
+
this.azimuthalCrown = null;
|
|
3096
|
+
this.securityCameraAnimator = null;
|
|
3097
|
+
this.noLightForObjects = true;
|
|
3098
|
+
}
|
|
3099
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportObject3DService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3100
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportObject3DService, providedIn: 'root' });
|
|
3101
|
+
}
|
|
3102
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportObject3DService, decorators: [{
|
|
3103
|
+
type: Injectable,
|
|
3104
|
+
args: [{
|
|
3105
|
+
providedIn: 'root',
|
|
3106
|
+
}]
|
|
3107
|
+
}], ctorParameters: () => [] });
|
|
3108
|
+
|
|
3109
|
+
class MatterportTagService {
|
|
3110
|
+
navigationService;
|
|
3111
|
+
dictionnaryTags = new Map();
|
|
3112
|
+
tagAddQueue = Promise.resolve();
|
|
3113
|
+
mattertagToFollow = null;
|
|
3114
|
+
onGoToTag = new Subject();
|
|
3115
|
+
mattertagIDs = [];
|
|
3116
|
+
tagsAttachments = {};
|
|
3117
|
+
tagMessengerOn = false;
|
|
3118
|
+
tagService = null;
|
|
3119
|
+
tagsCurrentOpacity = new Map();
|
|
3120
|
+
tagsCurrentEnabled = new Map();
|
|
3121
|
+
constructor(navigationService) {
|
|
3122
|
+
this.navigationService = navigationService;
|
|
3123
|
+
}
|
|
3124
|
+
setTagService(service) {
|
|
3125
|
+
this.tagService = service;
|
|
3126
|
+
}
|
|
3127
|
+
/** Opens a specific tag in the Matterport viewer by its ID. */
|
|
3128
|
+
async goToTag(sdk, sid) {
|
|
3129
|
+
if (!sdk)
|
|
3130
|
+
return;
|
|
3131
|
+
try {
|
|
3132
|
+
this.onGoToTag.next(sid);
|
|
3133
|
+
await sdk.Tag.open(sid);
|
|
3134
|
+
}
|
|
3135
|
+
catch (e) {
|
|
3136
|
+
if (isDevMode())
|
|
3137
|
+
console.warn('Cannot open tag', sid, e);
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
/** Opens the most recently created tag in the viewer. */
|
|
3141
|
+
async goToLastTag(sdk) {
|
|
3142
|
+
if (!sdk || this.mattertagIDs.length === 0)
|
|
3143
|
+
return;
|
|
3144
|
+
const lastSid = this.mattertagIDs[this.mattertagIDs.length - 1];
|
|
3145
|
+
return this.goToTag(sdk, lastSid);
|
|
3146
|
+
}
|
|
3147
|
+
/**
|
|
3148
|
+
* Adds a Mattertag to the viewer, serializing calls to prevent SDK race conditions.
|
|
3149
|
+
* Reuses existing IDs if the tag is already present in the session.
|
|
3150
|
+
*/
|
|
3151
|
+
async addMattertagToViewer(sdk, mattertagData) {
|
|
3152
|
+
if (!sdk)
|
|
3153
|
+
return null;
|
|
3154
|
+
this.tagAddQueue = this.tagAddQueue.then(async () => {
|
|
3155
|
+
const data = mattertagData.getData();
|
|
3156
|
+
const existingId = data?.id || null;
|
|
3157
|
+
try {
|
|
3158
|
+
const sidList = await sdk.Tag.add(data);
|
|
3159
|
+
if (sidList && sidList.length > 0) {
|
|
3160
|
+
const mattertagID = sidList[0];
|
|
3161
|
+
this.mattertagIDs.push(mattertagID);
|
|
3162
|
+
this.dictionnaryTags.set(mattertagID, mattertagData);
|
|
3163
|
+
return mattertagID;
|
|
3164
|
+
}
|
|
3165
|
+
}
|
|
3166
|
+
catch (error) {
|
|
3167
|
+
if (error?.message?.includes('already in use') && existingId) {
|
|
3168
|
+
if (!this.dictionnaryTags.has(existingId)) {
|
|
3169
|
+
this.mattertagIDs.push(existingId);
|
|
3170
|
+
this.dictionnaryTags.set(existingId, mattertagData);
|
|
3171
|
+
}
|
|
3172
|
+
return existingId;
|
|
3173
|
+
}
|
|
3174
|
+
if (isDevMode())
|
|
3175
|
+
console.warn('Failed to add tag to viewer', error);
|
|
3176
|
+
}
|
|
3177
|
+
return null;
|
|
3178
|
+
});
|
|
3179
|
+
return this.tagAddQueue;
|
|
3180
|
+
}
|
|
3181
|
+
/**
|
|
3182
|
+
* Internal method to add and configure a Mattertag with icon, opacity, and HTML content.
|
|
3183
|
+
* Handles existing tags gracefully and queues operations to avoid SDK conflicts.
|
|
3184
|
+
*/
|
|
3185
|
+
async _doAddMattertag(sdk, mattertagData, setTagIconAndOpacity, injectHtmlInTag) {
|
|
3186
|
+
const descriptor = mattertagData.getMattertagDescriptor();
|
|
3187
|
+
//console.log('descriptor', descriptor);
|
|
3188
|
+
const sid = descriptor[0]['id'];
|
|
3189
|
+
if (sid && this.dictionnaryTags.has(sid)) {
|
|
3190
|
+
await setTagIconAndOpacity(sid, mattertagData);
|
|
3191
|
+
await injectHtmlInTag(mattertagData.getType(), mattertagData.getObject(), sid);
|
|
3192
|
+
return sid;
|
|
3193
|
+
}
|
|
3194
|
+
this.tagAddQueue = this.tagAddQueue.then(async () => {
|
|
3195
|
+
try {
|
|
3196
|
+
const [createdSid] = await sdk.Tag.add(...descriptor);
|
|
3197
|
+
this.mattertagIDs.push(createdSid);
|
|
3198
|
+
this.dictionnaryTags.set(createdSid, mattertagData);
|
|
3199
|
+
await wait(100);
|
|
3200
|
+
await setTagIconAndOpacity(createdSid, mattertagData);
|
|
3201
|
+
injectHtmlInTag(mattertagData.getType(), mattertagData.getObject(), createdSid).catch(err => {
|
|
3202
|
+
if (isDevMode())
|
|
3203
|
+
console.warn('HTML injection failed for', createdSid, err);
|
|
3204
|
+
});
|
|
3205
|
+
return createdSid;
|
|
3206
|
+
}
|
|
3207
|
+
catch (e) {
|
|
3208
|
+
if (e?.message?.includes('already in use') && sid) {
|
|
3209
|
+
if (!this.dictionnaryTags.has(sid)) {
|
|
3210
|
+
this.mattertagIDs.push(sid);
|
|
3211
|
+
this.dictionnaryTags.set(sid, mattertagData);
|
|
3212
|
+
}
|
|
3213
|
+
await setTagIconAndOpacity(sid, mattertagData);
|
|
3214
|
+
await injectHtmlInTag(mattertagData.getType(), mattertagData.getObject(), sid);
|
|
3215
|
+
return sid;
|
|
3216
|
+
}
|
|
3217
|
+
throw e;
|
|
3218
|
+
}
|
|
3219
|
+
});
|
|
3220
|
+
return this.tagAddQueue;
|
|
3221
|
+
}
|
|
3222
|
+
getDistance(p1, p2) {
|
|
3223
|
+
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2) + Math.pow(p2.z - p1.z, 2));
|
|
3224
|
+
}
|
|
3225
|
+
/**
|
|
3226
|
+
* Checks if a tag is within the bounding box of any active room (adding a slight margin to account for wall-mounted tags).
|
|
3227
|
+
* If there are no active rooms (e.g., hallway), falls back to returning true.
|
|
3228
|
+
*/
|
|
3229
|
+
isTagInRooms(mattertagData, rooms) {
|
|
3230
|
+
if (!rooms || rooms.length === 0)
|
|
3231
|
+
return false;
|
|
3232
|
+
const tagPos = mattertagData.getPosition();
|
|
3233
|
+
const margin = 1.5;
|
|
3234
|
+
return rooms.some((room) => {
|
|
3235
|
+
if (!room.bounds)
|
|
3236
|
+
return false;
|
|
3237
|
+
const { min, max } = room.bounds;
|
|
3238
|
+
return (tagPos.x >= min.x - margin && tagPos.x <= max.x + margin &&
|
|
3239
|
+
tagPos.y >= min.y - margin && tagPos.y <= max.y + margin &&
|
|
3240
|
+
tagPos.z >= min.z - margin && tagPos.z <= max.z + margin);
|
|
3241
|
+
});
|
|
3242
|
+
}
|
|
3243
|
+
/**
|
|
3244
|
+
* Computes the final context-aware opacity for a single tag.
|
|
3245
|
+
* @param currentFloorSequence Authoritative current floor sequence from sdk.Floor.current
|
|
3246
|
+
* (null = single-floor model or unknown).
|
|
3247
|
+
* @param currentRooms Array of active rooms the camera is in.
|
|
3248
|
+
*/
|
|
3249
|
+
/*computeSingleTagContextOpacity(
|
|
3250
|
+
mattertagData: MattertagData,
|
|
3251
|
+
poseCamera: any,
|
|
3252
|
+
sweepCollection: any,
|
|
3253
|
+
currentFloorSequence: number | null,
|
|
3254
|
+
currentRooms: any[]
|
|
3255
|
+
): number {
|
|
3256
|
+
const mode = this.navigationService.currentCameraMode;
|
|
3257
|
+
|
|
3258
|
+
// 1. Check Floor
|
|
3259
|
+
const tagFloorId = this.getFloorIdForTag(mattertagData, sweepCollection);
|
|
3260
|
+
const currentFloorId = currentFloorSequence?.toString();
|
|
3261
|
+
if (tagFloorId && currentFloorId && tagFloorId !== currentFloorId) {
|
|
3262
|
+
return 0;
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
// 2. Si Dollhouse -> Pleine opacité
|
|
3266
|
+
//if (mode !== CameraMode.INSIDE) return 1;
|
|
3267
|
+
|
|
3268
|
+
// 3. Si Inside -> Check pièce + Distance progressive
|
|
3269
|
+
//if (!this.isTagInRooms(mattertagData, currentRooms)) return 0;
|
|
3270
|
+
|
|
3271
|
+
return 1;
|
|
3272
|
+
}*/
|
|
3273
|
+
/** Returns the ID of the most recently added tag. */
|
|
3274
|
+
getLastTag() {
|
|
3275
|
+
if (this.mattertagIDs.length === 0)
|
|
3276
|
+
return null;
|
|
3277
|
+
return this.mattertagIDs[this.mattertagIDs.length - 1];
|
|
3278
|
+
}
|
|
3279
|
+
/**
|
|
3280
|
+
* Updates the visibility (opacity) of all tags based on the current camera mode,
|
|
3281
|
+
* floor and room context. Must be called after each sweep, floor or mode change.
|
|
3282
|
+
*
|
|
3283
|
+
* Rules:
|
|
3284
|
+
* - DOLLHOUSE / FLOORPLAN → all tags hidden (opacity 0).
|
|
3285
|
+
* - INSIDE → only tags whose sweep belongs to the current floor are shown;
|
|
3286
|
+
* proximity-based opacity is applied via computeTagOpacity().
|
|
3287
|
+
* Tags on other floors are hidden (opacity 0).
|
|
3288
|
+
* - TRANSITIONING → no change (skip update to avoid flickering).
|
|
3289
|
+
*
|
|
3290
|
+
* @param sdk Matterport SDK instance.
|
|
3291
|
+
* @param poseCamera Current camera pose.
|
|
3292
|
+
* @param sweepCollection Full collection of sweeps.
|
|
3293
|
+
* @param currentCameraMode Current camera mode.
|
|
3294
|
+
* @param mattertagToFollow ID of the cursor tag (never touched).
|
|
3295
|
+
*/
|
|
3296
|
+
async updateTagsVisibilityForContext(sdk, sweepCollection, currentCameraMode, mattertagToFollow, currentFloorSequence = null, currentRooms = []) {
|
|
3297
|
+
if (!sdk || this.dictionnaryTags.size === 0)
|
|
3298
|
+
return;
|
|
3299
|
+
const isInteriorMode = currentCameraMode === CameraMode.INSIDE;
|
|
3300
|
+
const currentFloorId = currentFloorSequence !== null ? currentFloorSequence.toString() : null;
|
|
3301
|
+
const promises = [];
|
|
3302
|
+
for (const [tagId, mattertagData] of this.dictionnaryTags) {
|
|
3303
|
+
if (tagId === mattertagToFollow)
|
|
3304
|
+
continue;
|
|
3305
|
+
const tagFloorId = this.getFloorIdForTag(mattertagData, sweepCollection);
|
|
3306
|
+
const isOnCurrentFloor = !tagFloorId || !currentFloorId || tagFloorId === currentFloorId;
|
|
3307
|
+
let targetOpacity = 0;
|
|
3308
|
+
let shouldBeEnabled = false;
|
|
3309
|
+
// Calculation of opacity and enable status
|
|
3310
|
+
if (isOnCurrentFloor) {
|
|
3311
|
+
if (!isInteriorMode) {
|
|
3312
|
+
targetOpacity = 1;
|
|
3313
|
+
shouldBeEnabled = true;
|
|
3314
|
+
}
|
|
3315
|
+
else {
|
|
3316
|
+
targetOpacity = 0.9;
|
|
3317
|
+
shouldBeEnabled = true;
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
// Apply changes
|
|
3321
|
+
// Tooltip and click management
|
|
3322
|
+
const lastEnabled = this.tagsCurrentEnabled.get(tagId);
|
|
3323
|
+
if (lastEnabled !== shouldBeEnabled) {
|
|
3324
|
+
this.tagsCurrentEnabled.set(tagId, shouldBeEnabled);
|
|
3325
|
+
promises.push(sdk.Tag.allowAction(tagId, {
|
|
3326
|
+
opening: shouldBeEnabled,
|
|
3327
|
+
navigating: shouldBeEnabled,
|
|
3328
|
+
docking: false
|
|
3329
|
+
}).catch(() => { }));
|
|
3330
|
+
}
|
|
3331
|
+
// Opacity management
|
|
3332
|
+
const lastOpacity = this.tagsCurrentOpacity.get(tagId) ?? -1;
|
|
3333
|
+
if (Math.abs(lastOpacity - targetOpacity) > 0.05) {
|
|
3334
|
+
this.tagsCurrentOpacity.set(tagId, targetOpacity);
|
|
3335
|
+
promises.push(sdk.Tag.editOpacity(tagId, targetOpacity).catch(() => { }));
|
|
3336
|
+
}
|
|
2344
3337
|
}
|
|
2345
|
-
|
|
2346
|
-
this.mesh.position.set(this.inputs.localPosition.x, this.inputs.localPosition.y, this.inputs.localPosition.z);
|
|
2347
|
-
}
|
|
2348
|
-
onDestroy() {
|
|
2349
|
-
this.outputs.collider = null;
|
|
2350
|
-
this.outputs.objectRoot = null;
|
|
2351
|
-
this.mesh.material.dispose();
|
|
2352
|
-
this.mesh.geometry.dispose();
|
|
3338
|
+
await Promise.all(promises);
|
|
2353
3339
|
}
|
|
2354
|
-
|
|
2355
|
-
|
|
3340
|
+
/** Removes a specific tag from the viewer and local dictionaries. */
|
|
3341
|
+
async deleteMattertagFromId(sdk, mattertagID) {
|
|
3342
|
+
try {
|
|
3343
|
+
if (sdk)
|
|
3344
|
+
await sdk.Tag.remove(mattertagID);
|
|
3345
|
+
this.dictionnaryTags.delete(mattertagID);
|
|
3346
|
+
const index = this.mattertagIDs.indexOf(mattertagID);
|
|
3347
|
+
if (index > -1)
|
|
3348
|
+
this.mattertagIDs.splice(index, 1);
|
|
3349
|
+
}
|
|
3350
|
+
catch (e) {
|
|
3351
|
+
if (isDevMode())
|
|
3352
|
+
console.warn('Cannot delete tag', mattertagID, e);
|
|
3353
|
+
}
|
|
2356
3354
|
}
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
class CanvasRenderer extends SceneComponent {
|
|
2364
|
-
canvas;
|
|
2365
|
-
renderContext2D;
|
|
2366
|
-
inputs = {
|
|
2367
|
-
painter: null,
|
|
2368
|
-
textureRes: { w: 1024, h: 1024 }, // dim for thermostat
|
|
2369
|
-
};
|
|
2370
|
-
outputs = {
|
|
2371
|
-
texture: null,
|
|
2372
|
-
};
|
|
2373
|
-
events = {
|
|
2374
|
-
repaint: true,
|
|
2375
|
-
};
|
|
2376
|
-
onInit() {
|
|
2377
|
-
// set up canvas 2d context
|
|
2378
|
-
this.canvas = document.createElement('canvas');
|
|
2379
|
-
this.renderContext2D = this.canvas.getContext('2d');
|
|
2380
|
-
this.outputs.texture = new CanvasTexture(this.canvas);
|
|
2381
|
-
this.resize(this.inputs.textureRes);
|
|
2382
|
-
this.repaint();
|
|
3355
|
+
/** Removes the last added tag from the viewer. */
|
|
3356
|
+
async deleteLastMattertag(sdk) {
|
|
3357
|
+
const lastSid = this.getLastTag();
|
|
3358
|
+
if (lastSid)
|
|
3359
|
+
await this.deleteMattertagFromId(sdk, lastSid);
|
|
2383
3360
|
}
|
|
2384
|
-
|
|
2385
|
-
|
|
3361
|
+
/** Clears all tags from the viewer and resets local state. */
|
|
3362
|
+
async action_delete_all_mattertags(sdk) {
|
|
3363
|
+
if (sdk) {
|
|
3364
|
+
const sidsToRemove = [...this.mattertagIDs];
|
|
3365
|
+
for (const sid of sidsToRemove) {
|
|
3366
|
+
try {
|
|
3367
|
+
await sdk.Tag.remove(sid);
|
|
3368
|
+
}
|
|
3369
|
+
catch (e) { }
|
|
3370
|
+
}
|
|
3371
|
+
}
|
|
3372
|
+
this.clear();
|
|
2386
3373
|
}
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
3374
|
+
/**
|
|
3375
|
+
* Creates and configures a Mattertag from a POI, handling coordinates, normals, and sweep ID.
|
|
3376
|
+
* Skips creation if a tag for the object already exists.
|
|
3377
|
+
*/
|
|
3378
|
+
async createMattertagFromPOI(sdk, tagType, object, poi, poseCamera, getTagFromElementId, setTagIconAndOpacity, injectHtmlInTag) {
|
|
3379
|
+
const { tag } = getTagFromElementId(object.id);
|
|
3380
|
+
if (tag)
|
|
3381
|
+
return;
|
|
3382
|
+
const mattertagData = new MattertagData(tagType);
|
|
3383
|
+
mattertagData.setObject(object, tagType);
|
|
3384
|
+
if (poi.coordinate) {
|
|
3385
|
+
try {
|
|
3386
|
+
mattertagData.setPosition(JSON.parse(poi.coordinate));
|
|
3387
|
+
}
|
|
3388
|
+
catch (e) {
|
|
3389
|
+
if (isDevMode())
|
|
3390
|
+
console.warn('Error parsing POI coordinates', poi.coordinate);
|
|
3391
|
+
}
|
|
2391
3392
|
}
|
|
2392
|
-
if (
|
|
2393
|
-
|
|
3393
|
+
if (poi.metadata) {
|
|
3394
|
+
try {
|
|
3395
|
+
const tagMetadata = JSON.parse(poi.metadata);
|
|
3396
|
+
mattertagData.setNormal(tagMetadata.normal || { x: 0, y: -0.15, z: 0 });
|
|
3397
|
+
}
|
|
3398
|
+
catch (e) {
|
|
3399
|
+
mattertagData.setNormal({ x: 0, y: -0.15, z: 0 });
|
|
3400
|
+
}
|
|
2394
3401
|
}
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
if (eventType === 'repaint') {
|
|
2398
|
-
this.repaint();
|
|
3402
|
+
if (poi.matterportSweepID) {
|
|
3403
|
+
mattertagData.setSweepID(poi.matterportSweepID);
|
|
2399
3404
|
}
|
|
3405
|
+
mattertagData.setPoi(poi);
|
|
3406
|
+
const createdTagID = await this.addMattertagToViewer(sdk, mattertagData);
|
|
3407
|
+
if (createdTagID && sdk) {
|
|
3408
|
+
await wait(100);
|
|
3409
|
+
await setTagIconAndOpacity(createdTagID, mattertagData);
|
|
3410
|
+
injectHtmlInTag(tagType, object, createdTagID).catch(err => {
|
|
3411
|
+
if (isDevMode())
|
|
3412
|
+
console.warn('HTML injection failed for', createdTagID, err);
|
|
3413
|
+
});
|
|
3414
|
+
}
|
|
3415
|
+
return createdTagID;
|
|
2400
3416
|
}
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
this.
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
3417
|
+
/** Updates the icon, opacity, and HTML content of an existing tag. */
|
|
3418
|
+
async updateMatterTagContentForTagID(sdk, mattertagID, object, poiType, setTagIconAndOpacity, injectHtmlInTag) {
|
|
3419
|
+
const mattertagData = this.dictionnaryTags.get(mattertagID);
|
|
3420
|
+
if (!mattertagData)
|
|
3421
|
+
return;
|
|
3422
|
+
if (object) {
|
|
3423
|
+
mattertagData.setObject(object, poiType);
|
|
3424
|
+
}
|
|
3425
|
+
await setTagIconAndOpacity(mattertagID, mattertagData);
|
|
3426
|
+
await injectHtmlInTag(poiType, object, mattertagID);
|
|
2408
3427
|
}
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
3428
|
+
/** Registers a custom texture and applies it to a tag, optionally adjusting opacity. */
|
|
3429
|
+
async addNewIconAndSetForTag(sdk, mattertagID, iconPath, applyOpacity, opacity) {
|
|
3430
|
+
if (!sdk)
|
|
3431
|
+
return;
|
|
3432
|
+
try {
|
|
3433
|
+
const iconName = `custom-icon-${mattertagID}`;
|
|
3434
|
+
await sdk.Asset.registerTexture(iconName, iconPath);
|
|
3435
|
+
await sdk.Tag.editIcon(mattertagID, iconName);
|
|
3436
|
+
if (applyOpacity) {
|
|
3437
|
+
await sdk.Tag.editOpacity(mattertagID, opacity);
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
catch (error) {
|
|
3441
|
+
if (isDevMode())
|
|
3442
|
+
console.warn('Error setting custom icon or opacity', error);
|
|
2413
3443
|
}
|
|
2414
3444
|
}
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
const
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
inputs = {
|
|
2428
|
-
loadingState: 'Idle',
|
|
2429
|
-
texture: null,
|
|
2430
|
-
updateInterval: 1000,
|
|
2431
|
-
};
|
|
2432
|
-
events = {
|
|
2433
|
-
[HoverEvent]: true,
|
|
2434
|
-
[UnhoverEvent]: true,
|
|
2435
|
-
};
|
|
2436
|
-
intervalVideoTexture;
|
|
2437
|
-
onInit(modelNode) {
|
|
2438
|
-
if (!this.context) {
|
|
2439
|
-
this.context = {
|
|
2440
|
-
root: modelNode
|
|
2441
|
-
};
|
|
3445
|
+
/** Finds the tag ID and sweep ID associated with a specific element ID. */
|
|
3446
|
+
getTagFromElementId(elementID, sweeps) {
|
|
3447
|
+
let tagID = null;
|
|
3448
|
+
let sweepID = null;
|
|
3449
|
+
for (let [mattertagID, mattertagData] of this.dictionnaryTags) {
|
|
3450
|
+
if (mattertagData.elementID === elementID) {
|
|
3451
|
+
tagID = mattertagID;
|
|
3452
|
+
const sweep = mattertagData.getSweepID();
|
|
3453
|
+
if (sweep && sweeps && sweeps.includes(sweep)) {
|
|
3454
|
+
sweepID = sweep;
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
2442
3457
|
}
|
|
2443
|
-
|
|
2444
|
-
const THREE = this.context.three;
|
|
3458
|
+
return { tag: tagID, sweep: sweepID };
|
|
2445
3459
|
}
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
3460
|
+
/** Retrieves the floor identifier associated with a tag based on its sweep data.
|
|
3461
|
+
* Handles both the object form ({ floorInfo: { id, sequence }, floor: { id } })
|
|
3462
|
+
* and the primitive form (floor: number) used by Matterport SDK v3.
|
|
3463
|
+
*/
|
|
3464
|
+
getFloorIdForTag(mattertagData, sweepCollection) {
|
|
3465
|
+
const sweepId = mattertagData.getSweepID();
|
|
3466
|
+
if (!sweepId || !sweepCollection)
|
|
3467
|
+
return null;
|
|
3468
|
+
const sweepData = sweepCollection[sweepId];
|
|
3469
|
+
if (!sweepData)
|
|
3470
|
+
return null;
|
|
3471
|
+
// SDK v3: sweep.floor is a primitive number (the sequence index)
|
|
3472
|
+
if (typeof sweepData.floor === 'number') {
|
|
3473
|
+
return sweepData.floor.toString();
|
|
3474
|
+
}
|
|
3475
|
+
// Older / extended formats
|
|
3476
|
+
return sweepData?.floorInfo?.id
|
|
3477
|
+
?? sweepData?.floorInfo?.sequence?.toString()
|
|
3478
|
+
?? sweepData?.floorId
|
|
3479
|
+
?? sweepData?.floor?.id
|
|
3480
|
+
?? sweepData?.floor?.sequence?.toString()
|
|
3481
|
+
?? null;
|
|
2449
3482
|
}
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
3483
|
+
/**
|
|
3484
|
+
* Injects custom HTML or fallback billboard media into a Mattertag sandbox.
|
|
3485
|
+
* Attaches event listeners for interactive elements within the tag.
|
|
3486
|
+
*/
|
|
3487
|
+
async injectHtmlInTag(sdk, tagType, object, tagID) {
|
|
3488
|
+
if (!this.tagService) {
|
|
3489
|
+
console.error('[MatterportTagService] tagService is not initialized.');
|
|
3490
|
+
return;
|
|
3491
|
+
}
|
|
3492
|
+
try {
|
|
3493
|
+
let html = await this.tagService.getHtmlToInject(tagType, object);
|
|
3494
|
+
if (html && html.trim().length > 0 && sdk) {
|
|
3495
|
+
const scriptTag = this.tagService.getScriptForTag(object, tagType);
|
|
3496
|
+
html += `${scriptTag}`;
|
|
3497
|
+
const [sandboxId, messenger] = await sdk.Tag.registerSandbox(html);
|
|
3498
|
+
const attachmentID = this.tagsAttachments[tagID];
|
|
3499
|
+
if (attachmentID) {
|
|
3500
|
+
try {
|
|
3501
|
+
await sdk.Tag.detach(tagID, attachmentID);
|
|
3502
|
+
}
|
|
3503
|
+
catch (e) { }
|
|
2458
3504
|
}
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
const
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
this.context.renderer.render(this.context.scene, camera);
|
|
2491
|
-
};
|
|
2492
|
-
this.intervalVideoTexture = setInterval(() => {
|
|
2493
|
-
render();
|
|
2494
|
-
}, 180);
|
|
3505
|
+
this.tagsAttachments[tagID] = sandboxId;
|
|
3506
|
+
await sdk.Tag.attach(tagID, sandboxId);
|
|
3507
|
+
// Attach the "View informations" handler in tooltip
|
|
3508
|
+
messenger.on(TagAction.DETAIL_CLICK, this.tagService.onActionDetailClick.bind(this.tagService));
|
|
3509
|
+
messenger.on(TagAction.TICKET_CLICK, this.tagService.onActionDetailClick.bind(this.tagService));
|
|
3510
|
+
messenger.on(TagAction.AUDIO_CLICK, (audioCommentID) => this.tagService.onActionAudioClick(audioCommentID));
|
|
3511
|
+
messenger.on(TagAction.VIDEO_CLICK, (videoUrl) => this.tagService.onActionVideoClick(videoUrl));
|
|
3512
|
+
messenger.on(TagAction.IMAGE_CLICK, (imageCommentID) => this.tagService.onActionImageClick(imageCommentID));
|
|
3513
|
+
messenger.on(TagAction.DOC_CLICK, (docUrl) => this.tagService.onActionDocClick(docUrl));
|
|
3514
|
+
messenger.on(TagAction.YOUTUBE_CLICK, (youtubeUrl) => this.tagService.onActionYoutubeClick(youtubeUrl));
|
|
3515
|
+
}
|
|
3516
|
+
else if (sdk) {
|
|
3517
|
+
const { comment, tagDescription } = this.tagService.getBillboardMediaToEmbed(object);
|
|
3518
|
+
if (comment) {
|
|
3519
|
+
const attachmentID = await sdk.Tag.registerAttachment({
|
|
3520
|
+
type: 'media',
|
|
3521
|
+
data: {
|
|
3522
|
+
url: comment.externalLink,
|
|
3523
|
+
label: object.title || 'Media',
|
|
3524
|
+
},
|
|
3525
|
+
});
|
|
3526
|
+
await sdk.Tag.attach(tagID, attachmentID);
|
|
3527
|
+
const billboardAttachmentID = await sdk.Tag.registerAttachment({
|
|
3528
|
+
type: 'billboard',
|
|
3529
|
+
data: {
|
|
3530
|
+
title: object.title,
|
|
3531
|
+
description: tagDescription,
|
|
3532
|
+
},
|
|
3533
|
+
});
|
|
3534
|
+
await sdk.Tag.attach(tagID, billboardAttachmentID);
|
|
3535
|
+
this.tagsAttachments[tagID] = billboardAttachmentID;
|
|
2495
3536
|
}
|
|
2496
|
-
}
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
});
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
catch (error) {
|
|
3540
|
+
console.error('[MatterportTagService] Error in injectHtmlInTag:', error);
|
|
2501
3541
|
}
|
|
2502
3542
|
}
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
this.
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
this.
|
|
3543
|
+
/** Clears all local tag data and resets the addition queue. */
|
|
3544
|
+
clear() {
|
|
3545
|
+
this.dictionnaryTags.clear();
|
|
3546
|
+
this.tagAddQueue = Promise.resolve();
|
|
3547
|
+
this.mattertagToFollow = null;
|
|
3548
|
+
this.mattertagIDs = [];
|
|
2509
3549
|
}
|
|
3550
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagService, deps: [{ token: MatterportNavigationService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3551
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagService, providedIn: 'root' });
|
|
2510
3552
|
}
|
|
2511
|
-
|
|
2512
|
-
const makeTvPlayer = function () {
|
|
2513
|
-
return new TvPlayer();
|
|
2514
|
-
};
|
|
2515
|
-
|
|
2516
|
-
class BaseVisibilityService {
|
|
2517
|
-
detailShowing = new Subject();
|
|
2518
|
-
isChangePositionVisible = new Subject();
|
|
2519
|
-
constructor() { }
|
|
2520
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BaseVisibilityService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2521
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BaseVisibilityService, providedIn: 'root' });
|
|
2522
|
-
}
|
|
2523
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BaseVisibilityService, decorators: [{
|
|
3553
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagService, decorators: [{
|
|
2524
3554
|
type: Injectable,
|
|
2525
3555
|
args: [{
|
|
2526
3556
|
providedIn: 'root',
|
|
2527
3557
|
}]
|
|
2528
|
-
}], ctorParameters: () => [] });
|
|
3558
|
+
}], ctorParameters: () => [{ type: MatterportNavigationService }] });
|
|
2529
3559
|
|
|
2530
3560
|
class Config {
|
|
2531
3561
|
my_config;
|
|
@@ -2537,85 +3567,154 @@ class MatterportService {
|
|
|
2537
3567
|
activeRoute;
|
|
2538
3568
|
visibilityService;
|
|
2539
3569
|
ngZone;
|
|
2540
|
-
|
|
2541
|
-
|
|
3570
|
+
measurementService;
|
|
3571
|
+
navigationService;
|
|
3572
|
+
pointerService;
|
|
3573
|
+
object3DService;
|
|
3574
|
+
matterportTagService;
|
|
2542
3575
|
sdk;
|
|
2543
3576
|
container;
|
|
2544
3577
|
// Position camera
|
|
2545
3578
|
poseMatterport;
|
|
2546
3579
|
poseCamera;
|
|
2547
3580
|
lastCameraPosition = { x: 0.0, y: 0.0, z: 0.0 };
|
|
2548
|
-
azimuthalCrown;
|
|
2549
|
-
// Pointer trick
|
|
2550
|
-
pointerButton;
|
|
2551
|
-
// Display and get current position of cursor (for Admins only)
|
|
2552
|
-
getCursorPositionButton;
|
|
2553
|
-
cursorPositionButtonDisplayed = false;
|
|
2554
|
-
intervalCursorPointerPosition;
|
|
2555
|
-
textDisplayCursorPositionPanel;
|
|
2556
|
-
oldPoseMatterportPosition;
|
|
2557
|
-
// Measure mode
|
|
2558
3581
|
isMeasureModeOn = false;
|
|
2559
3582
|
interactionMode = ViewerInteractions.DEFAULT;
|
|
2560
|
-
|
|
2561
|
-
mattertagIDs
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
}
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
3583
|
+
cameraMode = 'INSIDE';
|
|
3584
|
+
get mattertagIDs() {
|
|
3585
|
+
return this.matterportTagService.mattertagIDs;
|
|
3586
|
+
}
|
|
3587
|
+
set mattertagIDs(value) {
|
|
3588
|
+
this.matterportTagService.mattertagIDs = value;
|
|
3589
|
+
}
|
|
3590
|
+
get dictionnaryTags() {
|
|
3591
|
+
return this.matterportTagService.dictionnaryTags;
|
|
3592
|
+
}
|
|
3593
|
+
get dictionnaryObjects3D() {
|
|
3594
|
+
return this.object3DService.dictionnaryObjects3D;
|
|
3595
|
+
}
|
|
3596
|
+
get dictionnarySceneObjects3D() {
|
|
3597
|
+
return this.object3DService.dictionnarySceneObjects3D;
|
|
3598
|
+
}
|
|
3599
|
+
get threeJSScene() {
|
|
3600
|
+
return this.object3DService.threeJSScene;
|
|
3601
|
+
}
|
|
3602
|
+
set threeJSScene(value) {
|
|
3603
|
+
this.object3DService.threeJSScene = value;
|
|
3604
|
+
}
|
|
3605
|
+
get azimuthalCrown() {
|
|
3606
|
+
return this.object3DService.azimuthalCrown;
|
|
3607
|
+
}
|
|
3608
|
+
set azimuthalCrown(value) {
|
|
3609
|
+
this.object3DService.azimuthalCrown = value;
|
|
3610
|
+
}
|
|
3611
|
+
get tagsAttachments() {
|
|
3612
|
+
return this.matterportTagService.tagsAttachments;
|
|
3613
|
+
}
|
|
3614
|
+
get sweeps() {
|
|
3615
|
+
return this.navigationService.sweeps;
|
|
3616
|
+
}
|
|
3617
|
+
set sweeps(value) {
|
|
3618
|
+
this.navigationService.sweeps = value;
|
|
3619
|
+
}
|
|
3620
|
+
get sweepCollection() {
|
|
3621
|
+
return this.navigationService.sweepCollection;
|
|
3622
|
+
}
|
|
3623
|
+
set sweepCollection(value) {
|
|
3624
|
+
this.navigationService.sweepCollection = value;
|
|
3625
|
+
}
|
|
3626
|
+
get currentSweep() {
|
|
3627
|
+
return this.navigationService.currentSweep;
|
|
3628
|
+
}
|
|
2581
3629
|
//camera position with rotation
|
|
2582
3630
|
currentCameraPose = new Subject();
|
|
2583
|
-
floors
|
|
3631
|
+
get floors() {
|
|
3632
|
+
return this.navigationService.floors;
|
|
3633
|
+
}
|
|
3634
|
+
set floors(value) {
|
|
3635
|
+
this.navigationService.floors = value;
|
|
3636
|
+
}
|
|
2584
3637
|
_currentSpaceID;
|
|
2585
|
-
lastObject3D
|
|
2586
|
-
|
|
3638
|
+
get lastObject3D() {
|
|
3639
|
+
return this.object3DService.lastObject3D;
|
|
3640
|
+
}
|
|
3641
|
+
set lastObject3D(value) {
|
|
3642
|
+
this.object3DService.lastObject3D = value;
|
|
3643
|
+
}
|
|
3644
|
+
get currentRooms() {
|
|
3645
|
+
return this.navigationService.currentRooms;
|
|
3646
|
+
}
|
|
3647
|
+
set currentRooms(value) {
|
|
3648
|
+
this.navigationService.currentRooms = value;
|
|
3649
|
+
}
|
|
2587
3650
|
get currentSpaceID() {
|
|
2588
3651
|
return this._currentSpaceID;
|
|
2589
3652
|
}
|
|
2590
3653
|
set currentSpaceID(value) {
|
|
2591
3654
|
this._currentSpaceID = value;
|
|
2592
3655
|
}
|
|
2593
|
-
|
|
2594
|
-
|
|
3656
|
+
get forbiddenSweeps() {
|
|
3657
|
+
return this.navigationService.forbiddenSweeps;
|
|
3658
|
+
}
|
|
3659
|
+
set forbiddenSweeps(value) {
|
|
3660
|
+
this.navigationService.forbiddenSweeps = value;
|
|
3661
|
+
}
|
|
2595
3662
|
tagAction = new Subject();
|
|
2596
|
-
mattertagToFollow
|
|
3663
|
+
get mattertagToFollow() {
|
|
3664
|
+
return this.matterportTagService.mattertagToFollow;
|
|
3665
|
+
}
|
|
3666
|
+
set mattertagToFollow(value) {
|
|
3667
|
+
this.matterportTagService.mattertagToFollow = value;
|
|
3668
|
+
}
|
|
3669
|
+
get inTransitionMode() {
|
|
3670
|
+
return this.navigationService.inTransitionMode;
|
|
3671
|
+
}
|
|
3672
|
+
set inTransitionMode(value) {
|
|
3673
|
+
this.navigationService.inTransitionMode = value;
|
|
3674
|
+
}
|
|
3675
|
+
get inTransitionSweep() {
|
|
3676
|
+
return this.navigationService.inTransitionSweep;
|
|
3677
|
+
}
|
|
3678
|
+
set inTransitionSweep(value) {
|
|
3679
|
+
this.navigationService.inTransitionSweep = value;
|
|
3680
|
+
}
|
|
3681
|
+
noLightForObjects = true;
|
|
3682
|
+
get currentCameraMode() {
|
|
3683
|
+
return this.navigationService.currentCameraMode;
|
|
3684
|
+
}
|
|
3685
|
+
set currentCameraMode(value) {
|
|
3686
|
+
this.navigationService.currentCameraMode = value;
|
|
3687
|
+
}
|
|
3688
|
+
get onCameraModeChanged() {
|
|
3689
|
+
return this.navigationService.onCameraModeChanged;
|
|
3690
|
+
}
|
|
3691
|
+
get onRoomChanged() {
|
|
3692
|
+
return this.navigationService.onRoomChanged;
|
|
3693
|
+
}
|
|
3694
|
+
get onGoToTag() {
|
|
3695
|
+
return this.matterportTagService.onGoToTag;
|
|
3696
|
+
}
|
|
2597
3697
|
tagService;
|
|
2598
3698
|
config;
|
|
2599
|
-
inTransitionMode = false;
|
|
2600
|
-
inTransitionSweep = false;
|
|
2601
|
-
noLightForObjects = true;
|
|
2602
|
-
currentCameraMode = CameraMode.OUTSIDE;
|
|
2603
|
-
onCameraModeChanged = new Subject();
|
|
2604
|
-
onGoToTag = new Subject();
|
|
2605
|
-
tagMessengerOn = false;
|
|
2606
3699
|
SPModule;
|
|
2607
|
-
objectControl
|
|
2608
|
-
|
|
3700
|
+
get objectControl() {
|
|
3701
|
+
return this.object3DService.objectControl;
|
|
3702
|
+
}
|
|
3703
|
+
get securityCameraAnimator() {
|
|
3704
|
+
return this.object3DService.securityCameraAnimator;
|
|
3705
|
+
}
|
|
2609
3706
|
/**
|
|
2610
3707
|
* Actions on left click when positioning mattertag in visit
|
|
2611
3708
|
*/
|
|
2612
|
-
pointerLeftClickHandler = () => {
|
|
3709
|
+
pointerLeftClickHandler = (evt) => {
|
|
2613
3710
|
if (this.mattertagToFollow) {
|
|
2614
3711
|
const mattertagData = this.dictionnaryTags.get(this.mattertagToFollow);
|
|
2615
|
-
mattertagData
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
3712
|
+
if (mattertagData) {
|
|
3713
|
+
mattertagData.setPosition({ ...this.poseMatterport.position });
|
|
3714
|
+
mattertagData.setNormal({ ...this.poseMatterport.normal });
|
|
3715
|
+
this.dictionnaryTags.set(this.mattertagToFollow, mattertagData);
|
|
3716
|
+
this.updateMatterTagContentForTagID(this.mattertagToFollow);
|
|
3717
|
+
}
|
|
2619
3718
|
}
|
|
2620
3719
|
this.onValidatedMattertag();
|
|
2621
3720
|
};
|
|
@@ -2625,52 +3724,25 @@ class MatterportService {
|
|
|
2625
3724
|
alert('action cancelled');
|
|
2626
3725
|
};
|
|
2627
3726
|
pointerMiddleClickHandler = (e) => {
|
|
2628
|
-
this.
|
|
2629
|
-
${this.pointToString(this.poseMatterport.position)}\n
|
|
2630
|
-
normal:
|
|
2631
|
-
${this.pointToString(this.poseMatterport.normal)}\n
|
|
2632
|
-
floorId:
|
|
2633
|
-
${this.poseMatterport.floorId}`;
|
|
2634
|
-
// this.textDisplayCursorPositionPanel.style.display = 'visible';
|
|
2635
|
-
this.getCursorPositionButton.style.display = 'none';
|
|
3727
|
+
this.pointerService.updateCursorDisplay(this.poseMatterport);
|
|
2636
3728
|
};
|
|
2637
|
-
constructor(config, router, activeRoute, visibilityService, ngZone) {
|
|
3729
|
+
constructor(config, router, activeRoute, visibilityService, ngZone, measurementService, navigationService, pointerService, object3DService, matterportTagService) {
|
|
2638
3730
|
this.router = router;
|
|
2639
3731
|
this.activeRoute = activeRoute;
|
|
2640
3732
|
this.visibilityService = visibilityService;
|
|
2641
3733
|
this.ngZone = ngZone;
|
|
3734
|
+
this.measurementService = measurementService;
|
|
3735
|
+
this.navigationService = navigationService;
|
|
3736
|
+
this.pointerService = pointerService;
|
|
3737
|
+
this.object3DService = object3DService;
|
|
3738
|
+
this.matterportTagService = matterportTagService;
|
|
2642
3739
|
this.config = config;
|
|
2643
|
-
// TODO: only for dev!
|
|
2644
|
-
if (!!this.getCursorPositionButton &&
|
|
2645
|
-
(document.location.href.indexOf('dev') !== -1 || document.location.href.indexOf('localhost') !== -1)) {
|
|
2646
|
-
this.intervalCursorPointerPosition = setInterval(() => {
|
|
2647
|
-
if (!this.poseMatterport) {
|
|
2648
|
-
return;
|
|
2649
|
-
}
|
|
2650
|
-
const nextShow = this.poseMatterport.time + 1000;
|
|
2651
|
-
if (new Date().getTime() > nextShow) {
|
|
2652
|
-
if (this.cursorPositionButtonDisplayed) {
|
|
2653
|
-
return;
|
|
2654
|
-
}
|
|
2655
|
-
const size = {
|
|
2656
|
-
w: this.container.clientWidth,
|
|
2657
|
-
h: this.container.clientHeight,
|
|
2658
|
-
};
|
|
2659
|
-
const coord = this.sdk.Conversion.worldToScreen(this.poseMatterport.position, this.poseCamera, size);
|
|
2660
|
-
this.getCursorPositionButton.style.left = `${coord.x - 25}px`;
|
|
2661
|
-
this.getCursorPositionButton.style.top = `${coord.y - 22}px`;
|
|
2662
|
-
this.getCursorPositionButton.style.display = 'block';
|
|
2663
|
-
// this.textDisplayCursorPositionPanel.style.display = 'none';
|
|
2664
|
-
this.cursorPositionButtonDisplayed = true;
|
|
2665
|
-
}
|
|
2666
|
-
}, 500);
|
|
2667
|
-
}
|
|
2668
3740
|
}
|
|
2669
3741
|
/**
|
|
2670
|
-
* Initializes Matterport and
|
|
2671
|
-
* @param tagService
|
|
2672
|
-
* @param module
|
|
2673
|
-
* @returns
|
|
3742
|
+
* Initializes the Matterport SDK, sets up event listeners, and configures assets.
|
|
3743
|
+
* @param tagService Service used to generate and inject HTML into tags.
|
|
3744
|
+
* @param module Application module (e.g., IMMO, MUSEUM) to enable specific features.
|
|
3745
|
+
* @returns Promise resolving to true when initialization is complete.
|
|
2674
3746
|
*/
|
|
2675
3747
|
async initSdk(tagService, module = SpModule.IMMO) {
|
|
2676
3748
|
if (this.sdk) {
|
|
@@ -2678,39 +3750,35 @@ class MatterportService {
|
|
|
2678
3750
|
await this.action_delete_all_mattertags();
|
|
2679
3751
|
}
|
|
2680
3752
|
this.tagService = tagService;
|
|
3753
|
+
this.matterportTagService.setTagService(tagService);
|
|
2681
3754
|
this.SPModule = module;
|
|
2682
3755
|
return new Promise((resolve, reject) => {
|
|
2683
3756
|
// Retrieve DOM elements
|
|
2684
|
-
|
|
3757
|
+
const pointerBtn = document.querySelector('#viewer-pointer-trick');
|
|
2685
3758
|
this.container = document.querySelector('#viewer-module');
|
|
2686
3759
|
const iframe = document.querySelector('#viewer-module');
|
|
2687
3760
|
if (!iframe) {
|
|
2688
3761
|
return;
|
|
2689
3762
|
}
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
this.
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
this.getCursorPositionButton = document.querySelector('#button');
|
|
2698
|
-
this.textDisplayCursorPositionPanel = document.querySelector('#text');
|
|
2699
|
-
if (this.getCursorPositionButton) {
|
|
2700
|
-
// get position on Matterport "model" on middle click
|
|
2701
|
-
this.getCursorPositionButton.addEventListener('click', this.pointerMiddleClickHandler);
|
|
2702
|
-
}
|
|
3763
|
+
const cursorBtn = document.querySelector('#button');
|
|
3764
|
+
const textPanel = document.querySelector('#text');
|
|
3765
|
+
this.pointerService.init(this.container, pointerBtn, cursorBtn, textPanel, {
|
|
3766
|
+
onLeftClick: this.pointerLeftClickHandler.bind(this),
|
|
3767
|
+
onRightClick: this.pointerRightClickHandler.bind(this),
|
|
3768
|
+
onMiddleClick: this.pointerMiddleClickHandler.bind(this),
|
|
3769
|
+
});
|
|
2703
3770
|
// Load SDK
|
|
2704
|
-
console.log('Loading Matterport SDK');
|
|
2705
3771
|
const showcaseWindow = iframe.contentWindow;
|
|
2706
|
-
iframe.addEventListener('load', async
|
|
3772
|
+
iframe.addEventListener('load', async () => {
|
|
2707
3773
|
try {
|
|
2708
|
-
this.sdk = await showcaseWindow.MP_SDK.connect(showcaseWindow, 'qn9wsasuy5h2fzrbrn1nzr0id', '
|
|
3774
|
+
this.sdk = await showcaseWindow.MP_SDK.connect(showcaseWindow, 'qn9wsasuy5h2fzrbrn1nzr0id', '');
|
|
2709
3775
|
}
|
|
2710
3776
|
catch (e) {
|
|
2711
3777
|
console.error(e);
|
|
2712
3778
|
return;
|
|
2713
3779
|
}
|
|
3780
|
+
this.addCustomCss();
|
|
3781
|
+
this.pointerService.startAdminCursorTracker(this.sdk, this.container, () => this.poseMatterport, () => this.poseCamera);
|
|
2714
3782
|
// Load Mattertag icons and custom subscriptions
|
|
2715
3783
|
switch (module) {
|
|
2716
3784
|
case SpModule.IMMO:
|
|
@@ -2721,17 +3789,11 @@ class MatterportService {
|
|
|
2721
3789
|
this.sdk.Asset.registerTexture('icon-object3d', this.config.my_config.icon_object3d);
|
|
2722
3790
|
this.sdk.Measurements.data.subscribe({
|
|
2723
3791
|
onAdded: function (index, item, collection) {
|
|
2724
|
-
|
|
2725
|
-
// "item added to the collection",
|
|
2726
|
-
// index,
|
|
2727
|
-
// item,
|
|
2728
|
-
// );
|
|
2729
|
-
// this.measurements[index] = item;
|
|
2730
|
-
this.lastMeasure = item.points;
|
|
3792
|
+
this.measurementService.setLastMeasure(item.points);
|
|
2731
3793
|
}.bind(this),
|
|
2732
3794
|
onCollectionUpdated: function (collection) {
|
|
2733
3795
|
// console.log('the entire up-to-date collection', collection);
|
|
2734
|
-
this.getDistanceForLastMeasurement();
|
|
3796
|
+
this.measurementService.getDistanceForLastMeasurement(this.sdk, this.currentSpaceID);
|
|
2735
3797
|
}.bind(this),
|
|
2736
3798
|
});
|
|
2737
3799
|
this.sdk.Measurements.mode.subscribe(function (measurementModeState) {
|
|
@@ -2755,7 +3817,11 @@ class MatterportService {
|
|
|
2755
3817
|
this.sdk.Asset.registerTexture('icon-position', this.config.my_config.icon_position);
|
|
2756
3818
|
// Current Room (used for getting bounding box and eventually lazy load mattertag or object3D inside current Room)
|
|
2757
3819
|
this.sdk.Room.current.subscribe((currentRoom) => {
|
|
2758
|
-
|
|
3820
|
+
const rooms = Array.isArray(currentRoom) ? currentRoom : (currentRoom ? [currentRoom] : []);
|
|
3821
|
+
this.currentRooms = rooms;
|
|
3822
|
+
this.navigationService.onRoomChanged.next(rooms);
|
|
3823
|
+
// Refresh tag visibility whenever the room context changes
|
|
3824
|
+
this.refreshTagsVisibility();
|
|
2759
3825
|
});
|
|
2760
3826
|
// 3D position's pointer
|
|
2761
3827
|
this.sdk.Pointer.intersection.subscribe(function (intersection) {
|
|
@@ -2768,64 +3834,41 @@ class MatterportService {
|
|
|
2768
3834
|
z: 0,
|
|
2769
3835
|
};
|
|
2770
3836
|
}
|
|
2771
|
-
if (this.interactionMode !== ViewerInteractions.DEFAULT &&
|
|
2772
|
-
this.mattertagToFollow) {
|
|
3837
|
+
if (this.interactionMode !== ViewerInteractions.DEFAULT && this.mattertagToFollow) {
|
|
2773
3838
|
// follow the pointer and changes the position of the last tag
|
|
2774
3839
|
// (we are about to validate, but it exists in sdk already)
|
|
2775
3840
|
this.enable_following_tag(this.mattertagToFollow);
|
|
2776
3841
|
}
|
|
2777
|
-
if (
|
|
2778
|
-
|
|
2779
|
-
this.getCursorPositionButton.style.display = 'none';
|
|
2780
|
-
this.cursorPositionButtonDisplayed = false;
|
|
3842
|
+
if (this.pointerService) {
|
|
3843
|
+
this.pointerService.setCursorPositionButtonDisplayed(false);
|
|
2781
3844
|
}
|
|
2782
3845
|
}.bind(this));
|
|
2783
3846
|
//Camera mode
|
|
2784
3847
|
this.sdk.Mode.current.subscribe((mode) => {
|
|
2785
|
-
this.
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
case 'mode.floorplan':
|
|
2791
|
-
this.currentCameraMode = CameraMode.FLOORPLAN;
|
|
2792
|
-
break;
|
|
2793
|
-
case 'mode.inside':
|
|
2794
|
-
this.currentCameraMode = CameraMode.INSIDE;
|
|
2795
|
-
break;
|
|
2796
|
-
case 'mode.transitioning':
|
|
2797
|
-
this.currentCameraMode = CameraMode.TRANSITIONING;
|
|
2798
|
-
break;
|
|
2799
|
-
default:
|
|
2800
|
-
this.currentCameraMode = CameraMode.OUTSIDE;
|
|
3848
|
+
if (this.cameraMode !== mode) {
|
|
3849
|
+
this.navigationService.setCameraMode(mode);
|
|
3850
|
+
// Refresh tag visibility on every mode change (INSIDE vs DOLLHOUSE vs FLOORPLAN)
|
|
3851
|
+
this.refreshTagsVisibility();
|
|
3852
|
+
this.cameraMode = mode;
|
|
2801
3853
|
}
|
|
2802
|
-
this.onCameraModeChanged.next(this.currentCameraMode);
|
|
2803
3854
|
});
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
// console.log('Rotation angle is ', pose.rotation);
|
|
2810
|
-
// console.log("Sweep UUID is", pose.sweep);
|
|
2811
|
-
}.bind(this));
|
|
3855
|
+
setTimeout(() => {
|
|
3856
|
+
if (this.sdk && this.poseCamera) {
|
|
3857
|
+
this.matterportTagService.updateTagsVisibilityForContext(this.sdk, this.sweepCollection, this.navigationService.currentCameraMode, this.mattertagToFollow, this.navigationService.currentFloorSequence, this.navigationService.currentRooms);
|
|
3858
|
+
}
|
|
3859
|
+
}, 1000);
|
|
2812
3860
|
// subscribe to sweeps
|
|
2813
3861
|
this.sdk.Sweep.data.subscribe({
|
|
2814
3862
|
onCollectionUpdated: function subscr(collection) {
|
|
2815
|
-
// console.log("Sweep collection updated");
|
|
2816
3863
|
this.sweeps = Object.keys(collection);
|
|
3864
|
+
this.sweepCollection = collection;
|
|
2817
3865
|
}.bind(this),
|
|
2818
3866
|
});
|
|
2819
3867
|
// subscribe to current sweep
|
|
2820
3868
|
this.sdk.Sweep.current.subscribe(function subscr(currentSweep) {
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
}
|
|
2825
|
-
else {
|
|
2826
|
-
// console.log("emmiting sweep", currentSweep.sid);
|
|
2827
|
-
this.currentSweep.next(currentSweep.sid);
|
|
2828
|
-
}
|
|
3869
|
+
if (currentSweep.sid === '')
|
|
3870
|
+
return;
|
|
3871
|
+
this.currentSweep.next(currentSweep.sid);
|
|
2829
3872
|
}.bind(this));
|
|
2830
3873
|
// Subscribe to Floor data
|
|
2831
3874
|
this.sdk.Floor.data.subscribe({
|
|
@@ -2833,25 +3876,23 @@ class MatterportService {
|
|
|
2833
3876
|
this.floors = Object.values(collection);
|
|
2834
3877
|
}.bind(this),
|
|
2835
3878
|
});
|
|
2836
|
-
//
|
|
2837
|
-
|
|
3879
|
+
// Subscribe to current floor – authoritative source for multi-floor filtering
|
|
3880
|
+
this.sdk.Floor.current.subscribe((currentFloor) => {
|
|
3881
|
+
const seq = currentFloor?.sequence ?? null;
|
|
3882
|
+
this.navigationService.currentFloorSequence = seq;
|
|
2838
3883
|
if (isDevMode()) {
|
|
2839
|
-
console.log(
|
|
3884
|
+
console.log('[Floor.current] sequence =', seq, '| full =', currentFloor);
|
|
2840
3885
|
}
|
|
2841
|
-
|
|
3886
|
+
this.refreshTagsVisibility();
|
|
3887
|
+
});
|
|
3888
|
+
// Generic handler for tag selection events
|
|
3889
|
+
const handleTagSelection = async (sid, source, evt) => {
|
|
2842
3890
|
try {
|
|
2843
3891
|
const mattertagData = this.dictionnaryTags.get(sid);
|
|
2844
|
-
if (!mattertagData)
|
|
2845
|
-
if (isDevMode()) {
|
|
2846
|
-
console.log('no mattertagData to display', sid);
|
|
2847
|
-
}
|
|
3892
|
+
if (!mattertagData)
|
|
2848
3893
|
return;
|
|
2849
|
-
}
|
|
2850
3894
|
const url = tagService.getUrlForSeeDetails(mattertagData.getObject(), mattertagData.getType());
|
|
2851
3895
|
if (url !== '') {
|
|
2852
|
-
if (isDevMode()) {
|
|
2853
|
-
console.log(`[MatterportService] Navigating to detail URL: ${url}`);
|
|
2854
|
-
}
|
|
2855
3896
|
this.visibilityService.detailShowing.next(true);
|
|
2856
3897
|
this.ngZone.run(() => {
|
|
2857
3898
|
this.router.navigate([url]);
|
|
@@ -2859,48 +3900,39 @@ class MatterportService {
|
|
|
2859
3900
|
}
|
|
2860
3901
|
}
|
|
2861
3902
|
catch (error) {
|
|
2862
|
-
if (isDevMode())
|
|
2863
|
-
console.
|
|
2864
|
-
}
|
|
3903
|
+
if (isDevMode())
|
|
3904
|
+
console.warn('Cannot show details for tag', error);
|
|
2865
3905
|
}
|
|
2866
3906
|
};
|
|
2867
|
-
//
|
|
3907
|
+
// Disable native Matterport actions
|
|
2868
3908
|
const disableNativeActions = (sid) => {
|
|
2869
|
-
if (!this.sdk)
|
|
2870
|
-
return;
|
|
3909
|
+
if (!this.sdk || sid === this.mattertagToFollow)
|
|
3910
|
+
return; // ignore when we are in positioning mode
|
|
2871
3911
|
try {
|
|
2872
|
-
if (this.sdk.Tag
|
|
2873
|
-
|
|
2874
|
-
// navigating: false désactive le déplacement de la caméra vers le tag
|
|
2875
|
-
this.sdk.Tag.allowAction(sid, { opening: false, navigating: true, docking: false });
|
|
2876
|
-
/*if (isDevMode()) {
|
|
2877
|
-
console.log(`[MatterportService] Disabled native actions for tag ${sid}`);
|
|
2878
|
-
}*/
|
|
2879
|
-
}
|
|
2880
|
-
else if (this.sdk.Mattertag && this.sdk.Mattertag.preventAction) {
|
|
2881
|
-
// Fallback ancienne API
|
|
2882
|
-
this.sdk.Mattertag.preventAction(sid, { opening: true, navigating: true });
|
|
2883
|
-
if (isDevMode()) {
|
|
2884
|
-
console.log(`[MatterportService] Prevented native actions (legacy) for tag ${sid}`);
|
|
2885
|
-
}
|
|
3912
|
+
if (this.sdk.Tag?.allowAction) {
|
|
3913
|
+
this.sdk.Tag.allowAction(sid, { opening: true, navigating: true, docking: false });
|
|
2886
3914
|
}
|
|
2887
3915
|
}
|
|
2888
3916
|
catch (e) {
|
|
2889
|
-
|
|
2890
|
-
|
|
3917
|
+
// silently ignore already removed tags
|
|
3918
|
+
if (isDevMode() && !e?.message?.includes('not found')) {
|
|
3919
|
+
console.warn('MatterportService: Error disabling actions for', sid, e);
|
|
2891
3920
|
}
|
|
2892
3921
|
}
|
|
2893
3922
|
};
|
|
2894
|
-
//
|
|
3923
|
+
// Wait for the application to reach PLAYING phase
|
|
2895
3924
|
if (this.sdk.App && this.sdk.App.state) {
|
|
2896
|
-
if (isDevMode()) {
|
|
2897
|
-
console.log('[MatterportService] Waiting for App.Phase.PLAYING...');
|
|
2898
|
-
}
|
|
2899
3925
|
this.sdk.App.state.waitUntil((s) => s.phase === this.sdk.App.Phase.PLAYING).then(() => {
|
|
2900
|
-
|
|
2901
|
-
|
|
3926
|
+
this.sdk.Camera.pose.subscribe((pose) => {
|
|
3927
|
+
this.poseCamera = pose;
|
|
3928
|
+
this.matterportTagService.updateTagsVisibilityForContext(this.sdk, this.sweepCollection, this.navigationService.currentCameraMode, this.mattertagToFollow, this.navigationService.currentFloorSequence, this.navigationService.currentRooms);
|
|
3929
|
+
});
|
|
3930
|
+
setTimeout(() => {
|
|
3931
|
+
this.matterportTagService.updateTagsVisibilityForContext(this.sdk, this.sweepCollection, this.navigationService.currentCameraMode, this.mattertagToFollow, this.navigationService.currentFloorSequence, this.navigationService.currentRooms);
|
|
3932
|
+
}, 1500);
|
|
3933
|
+
if (this.interactionMode === ViewerInteractions.DEFAULT) {
|
|
3934
|
+
this.navigationService.action_toolbox_inside_view(this.sdk);
|
|
2902
3935
|
}
|
|
2903
|
-
// 1. Désactiver les actions natives pour tous les tags existants et futurs
|
|
2904
3936
|
if (this.sdk.Tag && this.sdk.Tag.data) {
|
|
2905
3937
|
this.sdk.Tag.data.subscribe({
|
|
2906
3938
|
onAdded: (sid) => {
|
|
@@ -2910,21 +3942,14 @@ class MatterportService {
|
|
|
2910
3942
|
disableNativeActions(sid);
|
|
2911
3943
|
},
|
|
2912
3944
|
onCollectionUpdated: (collection) => {
|
|
2913
|
-
Object.keys(collection).forEach(sid => disableNativeActions(sid));
|
|
2914
|
-
}
|
|
2915
|
-
});
|
|
2916
|
-
}
|
|
2917
|
-
// 2. Écouter les sélections via l'observable openTags (Méthode moderne)
|
|
2918
|
-
if (this.sdk.Tag && this.sdk.Tag.openTags) {
|
|
2919
|
-
this.sdk.Tag.openTags.subscribe({
|
|
2920
|
-
onChanged: (newState) => {
|
|
2921
|
-
if (newState.selected && newState.selected.size > 0) {
|
|
2922
|
-
const sid = Array.from(newState.selected)[0];
|
|
2923
|
-
handleTagSelection(sid, 'Tag.openTags.selected');
|
|
2924
|
-
}
|
|
3945
|
+
Object.keys(collection).forEach((sid) => disableNativeActions(sid));
|
|
2925
3946
|
}
|
|
2926
3947
|
});
|
|
2927
3948
|
}
|
|
3949
|
+
resolve(true);
|
|
3950
|
+
})
|
|
3951
|
+
.catch((error) => {
|
|
3952
|
+
reject(error);
|
|
2928
3953
|
});
|
|
2929
3954
|
}
|
|
2930
3955
|
// Fallback pour l'événement global tag.click
|
|
@@ -2933,224 +3958,118 @@ class MatterportService {
|
|
|
2933
3958
|
console.log(`[MatterportService] sdk.on('tag.click') received for sid: ${sid}`);
|
|
2934
3959
|
}
|
|
2935
3960
|
handleTagSelection(sid, 'global.tag.click');
|
|
2936
|
-
// On s'assure qu'il est bien désactivé même si on a raté l'évènement d'ajout
|
|
2937
3961
|
disableNativeActions(sid);
|
|
2938
3962
|
});
|
|
2939
3963
|
// Pointer trick
|
|
2940
3964
|
// Create a div that will appear when the cursor is still
|
|
2941
3965
|
// It will intercept the click of the mouse before it trigerring the Matterport's tour navigation
|
|
2942
|
-
this.
|
|
3966
|
+
this.pointerService.startPointerTrick(this.sdk, this.container, () => this.poseMatterport, () => this.poseCamera, () => this.interactionMode, () => this.mattertagToFollow);
|
|
2943
3967
|
/**
|
|
2944
|
-
|
|
2945
|
-
|
|
3968
|
+
* Transitions
|
|
3969
|
+
*/
|
|
2946
3970
|
this.sdk.on('viewmode.changestart', function (to, from) {
|
|
2947
|
-
|
|
2948
|
-
this.inTransitionMode = true;
|
|
3971
|
+
console.debug('Starting to move to ' + to + ' from ' + from);
|
|
3972
|
+
this.navigationService.inTransitionMode = true;
|
|
2949
3973
|
}.bind(this));
|
|
2950
3974
|
this.sdk.on('viewmode.changeend', function (oldMode, newMode) {
|
|
2951
|
-
|
|
3975
|
+
console.debug('Ended to move to ' + newMode + ' from ' + oldMode);
|
|
2952
3976
|
if (newMode !== 'mode.transitioning') {
|
|
2953
|
-
this.inTransitionMode = false;
|
|
3977
|
+
this.navigationService.inTransitionMode = false;
|
|
2954
3978
|
}
|
|
2955
3979
|
}.bind(this));
|
|
2956
3980
|
this.sdk.on(this.sdk.Sweep.Event.ENTER, function (oldSweep, newSweep) {
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
this.inTransitionSweep = false;
|
|
3981
|
+
console.debug('Leaving sweep ' + oldSweep);
|
|
3982
|
+
console.debug('Entering sweep ' + newSweep);
|
|
3983
|
+
this.navigationService.inTransitionSweep = false;
|
|
2960
3984
|
this.displayAzimutalCrown();
|
|
3985
|
+
// Refresh on sweep is removed because we only update on room or floor changes now.
|
|
2961
3986
|
}.bind(this));
|
|
2962
3987
|
this.sdk.on(this.sdk.Sweep.Event.EXIT, function (fromSweep, toSweep) {
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
this.inTransitionSweep = true;
|
|
3988
|
+
console.debug('Leaving sweep ' + fromSweep);
|
|
3989
|
+
console.debug('Transitioning to sweep ' + toSweep);
|
|
3990
|
+
this.navigationService.inTransitionSweep = true;
|
|
2966
3991
|
}.bind(this));
|
|
2967
|
-
|
|
2968
|
-
const [sceneObject] = await this.sdk.Scene.createObjects(1);
|
|
2969
|
-
const node = sceneObject.addNode();
|
|
2970
|
-
node.start();
|
|
2971
|
-
this.threeJSScene = node.obj3D.parent;
|
|
2972
|
-
// await this.sdk.Scene.configure((renderer: any, three: any) => {
|
|
2973
|
-
// renderer.physicallyCorrectLights = true;
|
|
2974
|
-
// renderer.outputEncoding = three.sRGBEncoding;
|
|
2975
|
-
// renderer.shadowMap.enabled = true;
|
|
2976
|
-
// renderer.shadowMap.bias = 0.0001;
|
|
2977
|
-
// renderer.shadowMap.type = three.PCFSoftShadowMap;
|
|
2978
|
-
// });
|
|
2979
|
-
// TODO: wait for MP ticket resolution before decomment these!
|
|
2980
|
-
// Wait until Showcase is actually playing....
|
|
2981
|
-
// this.sdk.Tag.data.subscribe({
|
|
2982
|
-
// onAdded: async function (index, item, collection) {
|
|
2983
|
-
//
|
|
2984
|
-
// let thisOpacity = 0.2;
|
|
2985
|
-
// this.sdk.Tag.editOpacity(index, thisOpacity);
|
|
2986
|
-
//
|
|
2987
|
-
// let source = null;
|
|
2988
|
-
// try {
|
|
2989
|
-
// source = await Promise.all([
|
|
2990
|
-
// this.sdk.Sensor.createSource(this.sdk.Sensor.SourceType.SPHERE, {
|
|
2991
|
-
// origin: item.anchorPosition,
|
|
2992
|
-
// radius: Number(3),
|
|
2993
|
-
// userData: {
|
|
2994
|
-
// id: index + '-sphere-source',
|
|
2995
|
-
// },
|
|
2996
|
-
// })
|
|
2997
|
-
// ]);
|
|
2998
|
-
// } catch (e) {
|
|
2999
|
-
// console.log('could not create Sphere sensor')
|
|
3000
|
-
// console.error(e);
|
|
3001
|
-
// }
|
|
3002
|
-
// if (!source) {
|
|
3003
|
-
// return;
|
|
3004
|
-
// }
|
|
3005
|
-
//
|
|
3006
|
-
// let sensor = null;
|
|
3007
|
-
// try {
|
|
3008
|
-
// sensor = await this.sdk.Sensor.createSensor(this.sdk.Sensor.SensorType.CAMERA);
|
|
3009
|
-
// } catch (e) {
|
|
3010
|
-
// console.log('could not create Camera sensor')
|
|
3011
|
-
// console.error(e);
|
|
3012
|
-
// }
|
|
3013
|
-
// if (!sensor) {
|
|
3014
|
-
// return;
|
|
3015
|
-
// }
|
|
3016
|
-
//
|
|
3017
|
-
// sensor.addSource(...source);
|
|
3018
|
-
// sensor.readings.subscribe({
|
|
3019
|
-
// onUpdated(source, reading) {
|
|
3020
|
-
// console.log(thisOpacity);
|
|
3021
|
-
// let oldOpacity = thisOpacity;
|
|
3022
|
-
// if (reading.inRange) {
|
|
3023
|
-
// thisOpacity = 1;
|
|
3024
|
-
// console.log(index + ' is inRange');
|
|
3025
|
-
// } else if (reading.inView) {
|
|
3026
|
-
// console.log(index + ' is inView but not inRange');
|
|
3027
|
-
// thisOpacity = 0.5;
|
|
3028
|
-
// } else {
|
|
3029
|
-
// thisOpacity = 0.2;
|
|
3030
|
-
// console.log(index + ' is not inView or inRange');
|
|
3031
|
-
// }
|
|
3032
|
-
//
|
|
3033
|
-
// this.sdk.Tag.editOpacity(index, thisOpacity);
|
|
3034
|
-
// /*
|
|
3035
|
-
// let inc = 0.01;
|
|
3036
|
-
// if (oldOpacity > thisOpacity) {
|
|
3037
|
-
// inc = -0.01;
|
|
3038
|
-
// }
|
|
3039
|
-
//
|
|
3040
|
-
// for(var i = oldOpacity; i != thisOpacity; i=i+inc) {
|
|
3041
|
-
// setTimeout(function() {
|
|
3042
|
-
// mpSdk.Tag.editOpacity(index, i);
|
|
3043
|
-
// console.log('Delay', i);
|
|
3044
|
-
// },10);
|
|
3045
|
-
// }
|
|
3046
|
-
// */
|
|
3047
|
-
// }
|
|
3048
|
-
// });
|
|
3049
|
-
// //sensor.showDebug(true);
|
|
3050
|
-
// }.bind(this),
|
|
3051
|
-
// onCollectionUpdated: function (collection) {
|
|
3052
|
-
// console.log('Collection received. There are ', Object.keys(collection).length, ' Tags in the collection', collection);
|
|
3053
|
-
// }
|
|
3054
|
-
// });
|
|
3992
|
+
await this.init3DObjectViewer();
|
|
3055
3993
|
resolve(true);
|
|
3056
|
-
}
|
|
3994
|
+
});
|
|
3057
3995
|
});
|
|
3058
3996
|
}
|
|
3997
|
+
getSweepUUIDForSid(sid) {
|
|
3998
|
+
const collection = this.sweepCollection;
|
|
3999
|
+
if (!collection || !collection[sid])
|
|
4000
|
+
return null;
|
|
4001
|
+
return collection[sid].uuid ?? null;
|
|
4002
|
+
}
|
|
3059
4003
|
setLightingOff() {
|
|
3060
4004
|
this.noLightForObjects = true;
|
|
3061
4005
|
}
|
|
3062
|
-
pointToString(point) {
|
|
3063
|
-
var x = point.x.toFixed(3);
|
|
3064
|
-
var y = point.y.toFixed(3);
|
|
3065
|
-
var z = point.z.toFixed(3);
|
|
3066
|
-
return `{ x: ${x}, y: ${y}, z: ${z} }`;
|
|
3067
|
-
}
|
|
3068
|
-
//
|
|
3069
|
-
// ---------- Measurements related ----------
|
|
3070
|
-
//
|
|
3071
|
-
/**
|
|
3072
|
-
* Callback after measurement is performed
|
|
3073
|
-
*/
|
|
3074
4006
|
getDistanceForLastMeasurement() {
|
|
3075
|
-
|
|
3076
|
-
const numberPoints = this.lastMeasure.length;
|
|
3077
|
-
this.distancesLastMeasure = [];
|
|
3078
|
-
for (let index = 1; index < numberPoints; index += 1) {
|
|
3079
|
-
const distance = getDistanceBetweenTwoPoints(this.lastMeasure[index - 1], this.lastMeasure[index]);
|
|
3080
|
-
this.distancesLastMeasure.push(distance);
|
|
3081
|
-
}
|
|
3082
|
-
this.takeScreenShot().then((res) => {
|
|
3083
|
-
this.router.navigate([`visit/${this.currentSpaceID}/add_measurement`]);
|
|
3084
|
-
});
|
|
3085
|
-
}
|
|
4007
|
+
this.measurementService.getDistanceForLastMeasurement(this.sdk, this.currentSpaceID);
|
|
3086
4008
|
}
|
|
3087
4009
|
getLastDistances() {
|
|
3088
|
-
return this.
|
|
4010
|
+
return this.measurementService.getLastDistances();
|
|
3089
4011
|
}
|
|
3090
4012
|
/**
|
|
3091
4013
|
* Takes screenshot and saves base64 in lastScreenshotUri
|
|
3092
4014
|
* @returns Promise
|
|
3093
4015
|
*/
|
|
3094
4016
|
takeScreenShot() {
|
|
3095
|
-
return this.
|
|
3096
|
-
// base64 string
|
|
3097
|
-
this.lastScreenshotUri = screenShotUri;
|
|
3098
|
-
return Promise.resolve();
|
|
3099
|
-
}.bind(this));
|
|
4017
|
+
return this.measurementService.takeScreenShot(this.sdk);
|
|
3100
4018
|
}
|
|
3101
4019
|
getScreenShotUri() {
|
|
3102
|
-
return this.
|
|
4020
|
+
return this.measurementService.getScreenShotUri();
|
|
3103
4021
|
}
|
|
3104
4022
|
getLastMeasurement() {
|
|
3105
|
-
|
|
3106
|
-
measure: this.lastMeasure,
|
|
3107
|
-
sweep: this.poseCamera.sweep,
|
|
3108
|
-
};
|
|
3109
|
-
return data;
|
|
4023
|
+
return this.measurementService.getLastMeasurement(this.poseCamera);
|
|
3110
4024
|
}
|
|
3111
4025
|
//
|
|
3112
4026
|
// ---------- Utils ----------
|
|
3113
4027
|
//
|
|
4028
|
+
getFloorIdForTag(mattertagData) {
|
|
4029
|
+
return this.matterportTagService.getFloorIdForTag(mattertagData, this.sweepCollection);
|
|
4030
|
+
}
|
|
3114
4031
|
/**
|
|
3115
4032
|
* Styling of pointer
|
|
3116
4033
|
*/
|
|
3117
4034
|
updatePointerTrick() {
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
}
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
4035
|
+
this.pointerService.updatePointerTrick(this.sdk, this.container, this.poseMatterport, this.poseCamera, this.interactionMode, this.mattertagToFollow);
|
|
4036
|
+
}
|
|
4037
|
+
/**
|
|
4038
|
+
* Triggers a tag visibility refresh based on current camera mode, floor and sweep.
|
|
4039
|
+
* Delegates all logic to MatterportTagService.updateTagsVisibilityForContext().
|
|
4040
|
+
* Called automatically on Mode, Sweep, Floor and Room changes.
|
|
4041
|
+
*/
|
|
4042
|
+
refreshTagsVisibility() {
|
|
4043
|
+
Promise.resolve().then(() => {
|
|
4044
|
+
if (isDevMode() && this.sweepCollection && this.poseCamera?.sweep) {
|
|
4045
|
+
const sweepData = this.sweepCollection[this.poseCamera.sweep];
|
|
4046
|
+
console.debug('[refreshTagsVisibility] sweepData for current sweep:', JSON.stringify(sweepData));
|
|
4047
|
+
console.debug('[refreshTagsVisibility] currentFloorSequence:', this.navigationService.currentFloorSequence);
|
|
4048
|
+
console.debug('[refreshTagsVisibility] currentCameraMode:', this.currentCameraMode);
|
|
4049
|
+
}
|
|
4050
|
+
this.matterportTagService.updateTagsVisibilityForContext(this.sdk, this.sweepCollection, this.currentCameraMode, this.mattertagToFollow, this.navigationService.currentFloorSequence, this.navigationService.currentRooms).catch(err => {
|
|
4051
|
+
if (isDevMode())
|
|
4052
|
+
console.warn('[MatterportService] refreshTagsVisibility error', err);
|
|
4053
|
+
});
|
|
4054
|
+
});
|
|
3137
4055
|
}
|
|
3138
4056
|
/**
|
|
3139
4057
|
* Realtime mattertag following the cursor
|
|
3140
4058
|
* @param mattertag string
|
|
3141
4059
|
*/
|
|
3142
4060
|
enable_following_tag(mattertag) {
|
|
4061
|
+
const OFFSET = 0.0001; // quasi-invisible mais suffit à éviter l'interception
|
|
3143
4062
|
this.sdk.Tag.editPosition(mattertag, {
|
|
3144
4063
|
anchorPosition: {
|
|
3145
|
-
x: this.poseMatterport.position.x
|
|
3146
|
-
y: this.poseMatterport.position.y
|
|
3147
|
-
z: this.poseMatterport.position.z
|
|
4064
|
+
x: this.poseMatterport.position.x + OFFSET,
|
|
4065
|
+
y: this.poseMatterport.position.y,
|
|
4066
|
+
z: this.poseMatterport.position.z + OFFSET,
|
|
3148
4067
|
},
|
|
3149
4068
|
stemVector: {
|
|
3150
4069
|
x: this.poseMatterport.normal.x * 0.3,
|
|
3151
4070
|
y: this.poseMatterport.normal.y * 0.3,
|
|
3152
4071
|
z: this.poseMatterport.normal.z * 0.3,
|
|
3153
|
-
}
|
|
4072
|
+
}
|
|
3154
4073
|
});
|
|
3155
4074
|
}
|
|
3156
4075
|
/**
|
|
@@ -3160,58 +4079,46 @@ class MatterportService {
|
|
|
3160
4079
|
* @param pos2
|
|
3161
4080
|
*/
|
|
3162
4081
|
getDistPosition(pos1, pos2) {
|
|
3163
|
-
|
|
3164
|
-
w: this.container.clientWidth,
|
|
3165
|
-
h: this.container.clientHeight,
|
|
3166
|
-
};
|
|
3167
|
-
const coords1 = this.sdk.Conversion.worldToScreen(pos1, this.poseCamera, size);
|
|
3168
|
-
const coords2 = this.sdk.Conversion.worldToScreen(pos2, this.poseCamera, size);
|
|
3169
|
-
return Math.sqrt((coords1.x - coords2.x) ** 2 + (coords1.y - coords2.y) ** 2);
|
|
4082
|
+
return this.pointerService.getDistPosition(this.sdk, this.container, this.poseCamera, pos1, pos2);
|
|
3170
4083
|
}
|
|
3171
4084
|
//
|
|
3172
4085
|
// ---------- Mattertag related ----------
|
|
3173
4086
|
//
|
|
3174
|
-
/**
|
|
3175
|
-
* Creates the Mattertag that will follow the cursor
|
|
3176
|
-
* @param mattertagData MattertagData
|
|
3177
|
-
*/
|
|
4087
|
+
/** Creates a temporary Mattertag that follows the user's cursor for positioning. */
|
|
3178
4088
|
async addCursorMattertag(mattertagData) {
|
|
3179
4089
|
if (!this.poseMatterport)
|
|
3180
4090
|
return;
|
|
3181
4091
|
this.mattertagToFollow = await this.addMattertagToViewer(mattertagData);
|
|
3182
|
-
|
|
4092
|
+
await wait(50);
|
|
3183
4093
|
this.sdk.Tag.editIcon(this.mattertagToFollow, 'icon-position');
|
|
3184
4094
|
this.sdk.Tag.editOpacity(this.mattertagToFollow, 1);
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
let sidList;
|
|
3194
|
-
if (!this.sdk) {
|
|
3195
|
-
return null;
|
|
3196
|
-
}
|
|
4095
|
+
this.sdk.Tag.editPosition(this.mattertagToFollow, {
|
|
4096
|
+
anchorPosition: { ...this.poseMatterport.position },
|
|
4097
|
+
stemVector: {
|
|
4098
|
+
x: this.poseMatterport.normal.x * 0.3,
|
|
4099
|
+
y: this.poseMatterport.normal.y * 0.3,
|
|
4100
|
+
z: this.poseMatterport.normal.z * 0.3,
|
|
4101
|
+
}
|
|
4102
|
+
});
|
|
3197
4103
|
try {
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
if (sidList) {
|
|
3204
|
-
const mattertagID = sidList[0];
|
|
3205
|
-
// console.log("added tag", mattertagData.getType(), mattertagID);
|
|
3206
|
-
this.mattertagIDs.push(mattertagID);
|
|
3207
|
-
this.dictionnaryTags.set(mattertagID, mattertagData);
|
|
3208
|
-
return mattertagID;
|
|
4104
|
+
await this.sdk.Tag.allowAction(this.mattertagToFollow, {
|
|
4105
|
+
opening: true,
|
|
4106
|
+
navigating: false,
|
|
4107
|
+
docking: false
|
|
4108
|
+
});
|
|
3209
4109
|
}
|
|
3210
|
-
|
|
4110
|
+
catch (e) { }
|
|
3211
4111
|
}
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
4112
|
+
get tagAddQueue() {
|
|
4113
|
+
return this.matterportTagService.tagAddQueue;
|
|
4114
|
+
}
|
|
4115
|
+
set tagAddQueue(value) {
|
|
4116
|
+
this.matterportTagService.tagAddQueue = value;
|
|
4117
|
+
}
|
|
4118
|
+
async addMattertagToViewer(mattertagData) {
|
|
4119
|
+
return this.matterportTagService.addMattertagToViewer(this.sdk, mattertagData);
|
|
4120
|
+
}
|
|
4121
|
+
/** Triggers callback actions after a tag's position is validated by a left click. */
|
|
3215
4122
|
onValidatedMattertag() {
|
|
3216
4123
|
this.setInteractionMode(ViewerInteractions.DEFAULT);
|
|
3217
4124
|
const lastTag = this.getLastTag();
|
|
@@ -3222,34 +4129,21 @@ class MatterportService {
|
|
|
3222
4129
|
this.callbackAfterMattertagValidation(callbackMode);
|
|
3223
4130
|
}
|
|
3224
4131
|
}
|
|
3225
|
-
/**
|
|
3226
|
-
* Registers new icon (path to image) and set its for Mattertag
|
|
3227
|
-
* @param mattertagID string
|
|
3228
|
-
* @param iconPath string
|
|
3229
|
-
*/
|
|
4132
|
+
/** Registers a new icon texture and applies it to a specific Mattertag. */
|
|
3230
4133
|
async addNewIconAndSetForTag(mattertagID, iconPath) {
|
|
3231
|
-
await this.
|
|
3232
|
-
this.sdk.Tag.editIcon(mattertagID, `icon_${mattertagID}`);
|
|
4134
|
+
await this.matterportTagService.addNewIconAndSetForTag(this.sdk, mattertagID, iconPath, false, 1);
|
|
3233
4135
|
}
|
|
3234
|
-
/**
|
|
3235
|
-
* Changes icon of Mattertag (the iconName should be registered = one of default ones)
|
|
3236
|
-
* @param mattertagID string
|
|
3237
|
-
* @param iconName string
|
|
3238
|
-
*/
|
|
4136
|
+
/** Applies a pre-registered icon to a Mattertag. */
|
|
3239
4137
|
async setRegistredIconForTag(mattertagID, iconName) {
|
|
3240
4138
|
try {
|
|
3241
4139
|
this.sdk.Tag.editIcon(mattertagID, iconName);
|
|
3242
4140
|
}
|
|
3243
4141
|
catch (e) {
|
|
3244
|
-
|
|
4142
|
+
if (isDevMode())
|
|
4143
|
+
console.warn('Could not edit icon', iconName, e);
|
|
3245
4144
|
}
|
|
3246
4145
|
}
|
|
3247
|
-
/**
|
|
3248
|
-
* Sets default icon for a tag (registered in initSdk) OR uses tagIcon from POI (available from MattertagData)
|
|
3249
|
-
* @param mattertagID string
|
|
3250
|
-
* @param mattertagData MattertagData
|
|
3251
|
-
* @returns
|
|
3252
|
-
*/
|
|
4146
|
+
/** Sets the appropriate icon and opacity for a tag based on its type and POI metadata. */
|
|
3253
4147
|
async setTagIconAndOpacity(mattertagID, mattertagData) {
|
|
3254
4148
|
if (this.SPModule === SpModule.HOTEL) {
|
|
3255
4149
|
const room = mattertagData.getObject();
|
|
@@ -3294,36 +4188,89 @@ class MatterportService {
|
|
|
3294
4188
|
}
|
|
3295
4189
|
try {
|
|
3296
4190
|
this.sdk.Tag.editIcon(mattertagID, iconName);
|
|
3297
|
-
this.sdk.Tag.editOpacity(mattertagID, opacity);
|
|
3298
4191
|
}
|
|
3299
4192
|
catch (error) {
|
|
3300
4193
|
console.log('Error editIcon or opacity', error);
|
|
3301
4194
|
}
|
|
3302
4195
|
}
|
|
3303
|
-
/**
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
goToLastTag() {
|
|
3307
|
-
setTimeout(() => {
|
|
3308
|
-
const lastTag = this.getLastTag();
|
|
3309
|
-
this.goToTag(lastTag);
|
|
3310
|
-
}, 2000);
|
|
4196
|
+
/** Navigates the camera to the most recently created tag. */
|
|
4197
|
+
async goToLastTag() {
|
|
4198
|
+
await this.matterportTagService.goToLastTag(this.sdk);
|
|
3311
4199
|
}
|
|
3312
|
-
/**
|
|
3313
|
-
* Moves viewer to Mattertag with ID provided
|
|
3314
|
-
* @param mattertagID string
|
|
3315
|
-
* @returns
|
|
3316
|
-
*/
|
|
4200
|
+
/** Navigates the camera to a specific Mattertag by its ID. */
|
|
3317
4201
|
async goToTag(mattertagID) {
|
|
3318
|
-
if (mattertagID
|
|
4202
|
+
if (!mattertagID /* || this.inTransitionSweep*/) {
|
|
3319
4203
|
return;
|
|
4204
|
+
}
|
|
3320
4205
|
try {
|
|
3321
4206
|
this.onGoToTag.next(mattertagID);
|
|
3322
4207
|
await this.sdk.Sweep.current.waitUntil((currentSweep) => currentSweep !== '');
|
|
3323
|
-
|
|
4208
|
+
const mtData = this.dictionnaryTags.get(mattertagID);
|
|
4209
|
+
if (mtData) {
|
|
4210
|
+
const position = mtData.getPosition();
|
|
4211
|
+
await this.sdk.Camera.lookAt(position, {
|
|
4212
|
+
transition: this.sdk.Camera.TransitionType.FLY
|
|
4213
|
+
});
|
|
4214
|
+
await this.sdk.Tag.open(mattertagID);
|
|
4215
|
+
}
|
|
4216
|
+
else {
|
|
4217
|
+
// Fallback for cases where we don't have local data yet
|
|
4218
|
+
await this.sdk.Tag.open(mattertagID);
|
|
4219
|
+
}
|
|
3324
4220
|
}
|
|
3325
4221
|
catch (error) {
|
|
3326
|
-
|
|
4222
|
+
if (isDevMode())
|
|
4223
|
+
console.warn('Cannot navigate to tag', error);
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
/**
|
|
4227
|
+
* Computes the context-aware opacity for a single tag at the moment it is rendered.
|
|
4228
|
+
* - Cursor tag: always use provided defaultOpacity.
|
|
4229
|
+
* - DOLLHOUSE / FLOORPLAN: 0 (hidden).
|
|
4230
|
+
* - INSIDE: floor-filtered proximity opacity via MatterportTagService.
|
|
4231
|
+
* - Other / unknown: defaultOpacity.
|
|
4232
|
+
*/
|
|
4233
|
+
/*private _computeContextOpacityForTag(
|
|
4234
|
+
mattertagID: string,
|
|
4235
|
+
mattertagData: MattertagData,
|
|
4236
|
+
defaultOpacity: number
|
|
4237
|
+
): number {
|
|
4238
|
+
if (mattertagID === this.mattertagToFollow) {
|
|
4239
|
+
return defaultOpacity;
|
|
4240
|
+
}
|
|
4241
|
+
return this.matterportTagService.computeSingleTagContextOpacity(
|
|
4242
|
+
mattertagData,
|
|
4243
|
+
this.poseCamera,
|
|
4244
|
+
this.sweepCollection,
|
|
4245
|
+
this.navigationService.currentFloorSequence,
|
|
4246
|
+
this.navigationService.currentRooms
|
|
4247
|
+
);
|
|
4248
|
+
}*/
|
|
4249
|
+
addCustomCss() {
|
|
4250
|
+
const css = `
|
|
4251
|
+
.footer-ui,
|
|
4252
|
+
.showcase-footer,
|
|
4253
|
+
.mp-nova-btn-group,
|
|
4254
|
+
.footer-divider,
|
|
4255
|
+
.logo-link,
|
|
4256
|
+
.footer-logo,
|
|
4257
|
+
.bottom-ui,
|
|
4258
|
+
[data-testid="showcase-footer"] {
|
|
4259
|
+
opacity: 0 !important;
|
|
4260
|
+
visibility: hidden !important;
|
|
4261
|
+
pointer-events: none !important;
|
|
4262
|
+
}
|
|
4263
|
+
`;
|
|
4264
|
+
// 1st method: Via Scene SDK
|
|
4265
|
+
if (this.sdk?.Scene?.addStyle) {
|
|
4266
|
+
this.sdk.Scene.addStyle(css);
|
|
4267
|
+
}
|
|
4268
|
+
// 2nd method: Direct injection in iFrame DOM (Fallback)
|
|
4269
|
+
const iframe = document.querySelector('#viewer-module');
|
|
4270
|
+
if (iframe?.contentWindow?.document) {
|
|
4271
|
+
const style = iframe.contentWindow.document.createElement('style');
|
|
4272
|
+
style.textContent = css;
|
|
4273
|
+
iframe.contentWindow.document.head.appendChild(style);
|
|
3327
4274
|
}
|
|
3328
4275
|
}
|
|
3329
4276
|
/**
|
|
@@ -3333,11 +4280,18 @@ class MatterportService {
|
|
|
3333
4280
|
* @param tagType PoiType
|
|
3334
4281
|
*/
|
|
3335
4282
|
async updateMatterTagContentForTagID(mattertagID, object = null, tagType = null) {
|
|
3336
|
-
this.sdk
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
await this.
|
|
4283
|
+
if (this.sdk) {
|
|
4284
|
+
await this.sdk.Tag.editBillboard(mattertagID, this.dictionnaryTags.get(mattertagID).getData());
|
|
4285
|
+
}
|
|
4286
|
+
// Mise à jour de l'icône immédiate
|
|
4287
|
+
await this.matterportTagService.updateMatterTagContentForTagID(this.sdk, mattertagID, object, tagType, this.setTagIconAndOpacity.bind(this),
|
|
4288
|
+
// On passe une fonction wrapper qui exécute l'injection HTML sans bloquer
|
|
4289
|
+
async (type, obj, sid) => {
|
|
4290
|
+
this.injectHtmlInTag(type, obj, sid).catch(err => {
|
|
4291
|
+
if (isDevMode())
|
|
4292
|
+
console.warn('Async HTML update failed for', sid, err);
|
|
4293
|
+
});
|
|
4294
|
+
});
|
|
3341
4295
|
}
|
|
3342
4296
|
/**
|
|
3343
4297
|
* Updates injected html for Mattertag
|
|
@@ -3353,17 +4307,13 @@ class MatterportService {
|
|
|
3353
4307
|
* @param mattertagID string
|
|
3354
4308
|
*/
|
|
3355
4309
|
deleteMattertagFromId(mattertagID) {
|
|
3356
|
-
this.
|
|
3357
|
-
this.dictionnaryTags.delete(mattertagID);
|
|
4310
|
+
this.matterportTagService.deleteMattertagFromId(this.sdk, mattertagID);
|
|
3358
4311
|
}
|
|
3359
4312
|
/**
|
|
3360
4313
|
* Deletes latest created mattertag
|
|
3361
4314
|
*/
|
|
3362
|
-
deleteLastMattertag() {
|
|
3363
|
-
|
|
3364
|
-
if (mattertagID) {
|
|
3365
|
-
this.deleteMattertagFromId(mattertagID);
|
|
3366
|
-
}
|
|
4315
|
+
async deleteLastMattertag() {
|
|
4316
|
+
await this.matterportTagService.deleteLastMattertag(this.sdk);
|
|
3367
4317
|
}
|
|
3368
4318
|
/**
|
|
3369
4319
|
* Legacy: used to be called action_add_mattertag_from_POI
|
|
@@ -3374,35 +4324,7 @@ class MatterportService {
|
|
|
3374
4324
|
* @returns
|
|
3375
4325
|
*/
|
|
3376
4326
|
async createMattertagFromPOI(tagType, object, poi) {
|
|
3377
|
-
|
|
3378
|
-
const { tag, sweep } = this.getTagFromElementId(object.id);
|
|
3379
|
-
if (tag) {
|
|
3380
|
-
// console.log("tag exists", object)
|
|
3381
|
-
return;
|
|
3382
|
-
}
|
|
3383
|
-
const mattertagData = new MattertagData(tagType);
|
|
3384
|
-
mattertagData.setObject(object, tagType);
|
|
3385
|
-
if (poi.coordinate) {
|
|
3386
|
-
mattertagData.setPosition(JSON.parse(poi.coordinate));
|
|
3387
|
-
}
|
|
3388
|
-
if (poi.metadata) {
|
|
3389
|
-
const tagMetadata = JSON.parse(poi.metadata);
|
|
3390
|
-
if (tagMetadata.normal) {
|
|
3391
|
-
mattertagData.setNormal(tagMetadata.normal);
|
|
3392
|
-
}
|
|
3393
|
-
else {
|
|
3394
|
-
mattertagData.setNormal({ x: 0, y: -0.15, z: 0 });
|
|
3395
|
-
}
|
|
3396
|
-
}
|
|
3397
|
-
if (poi.matterportSweepID) {
|
|
3398
|
-
mattertagData.setSweepID(poi.matterportSweepID);
|
|
3399
|
-
}
|
|
3400
|
-
mattertagData.setPoi(poi);
|
|
3401
|
-
const createdTagID = await this.addMattertagToViewer(mattertagData);
|
|
3402
|
-
if (createdTagID && this.sdk) {
|
|
3403
|
-
await this.setTagIconAndOpacity(createdTagID, mattertagData);
|
|
3404
|
-
await this.injectHtmlInTag(tagType, object, createdTagID);
|
|
3405
|
-
}
|
|
4327
|
+
return this.matterportTagService.createMattertagFromPOI(this.sdk, tagType, object, poi, this.poseCamera, this.getTagFromElementId.bind(this), this.setTagIconAndOpacity.bind(this), this.injectHtmlInTag.bind(this));
|
|
3406
4328
|
}
|
|
3407
4329
|
/**
|
|
3408
4330
|
* Inject custom HTML as Mattertag content
|
|
@@ -3411,63 +4333,10 @@ class MatterportService {
|
|
|
3411
4333
|
* @param tagID string
|
|
3412
4334
|
*/
|
|
3413
4335
|
async injectHtmlInTag(tagType, object, tagID) {
|
|
3414
|
-
|
|
3415
|
-
if (html !== '' && this.sdk) {
|
|
3416
|
-
const scriptTag = this.tagService.getScriptForTag(object, tagType);
|
|
3417
|
-
html += `${scriptTag}`;
|
|
3418
|
-
// create and register the sandbox
|
|
3419
|
-
const [sandboxId, messenger] = await this.sdk.Tag.registerSandbox(html);
|
|
3420
|
-
// detach previous sandbox from a tag
|
|
3421
|
-
let attachmentID = this.tagsAttachments[tagID];
|
|
3422
|
-
if (attachmentID) {
|
|
3423
|
-
this.sdk.Tag.detach(tagID, attachmentID);
|
|
3424
|
-
}
|
|
3425
|
-
this.tagsAttachments[tagID] = sandboxId;
|
|
3426
|
-
// attach the sandbox to a tag
|
|
3427
|
-
this.sdk.Tag.attach(tagID, sandboxId);
|
|
3428
|
-
// receive data from the sandbox
|
|
3429
|
-
// tagMessengerOn allows to go here only once
|
|
3430
|
-
if (!this.tagMessengerOn) {
|
|
3431
|
-
this.tagMessengerOn = true;
|
|
3432
|
-
const imageClick = (featureID) => {
|
|
3433
|
-
// console.log("image click handler", featureID);
|
|
3434
|
-
this.tagService.onActionImageClick(featureID);
|
|
3435
|
-
};
|
|
3436
|
-
const audioClick = (audioCommentID) => {
|
|
3437
|
-
// console.log("audio click handler", audioCommentID);
|
|
3438
|
-
this.tagService.onActionAudioClick(audioCommentID);
|
|
3439
|
-
};
|
|
3440
|
-
const videoClick = (url) => {
|
|
3441
|
-
this.tagService.onActionVideoClick(url);
|
|
3442
|
-
};
|
|
3443
|
-
messenger.on(TagAction.DETAIL_CLICK, this.tagService.onActionDetailClick.bind(this.tagService));
|
|
3444
|
-
messenger.on(TagAction.TICKET_CLICK, this.tagService.onActionDetailClick.bind(this.tagService));
|
|
3445
|
-
messenger.on(TagAction.AUDIO_CLICK, audioClick);
|
|
3446
|
-
messenger.on(TagAction.IMAGE_CLICK, imageClick);
|
|
3447
|
-
messenger.on(TagAction.VIDEO_CLICK, videoClick);
|
|
3448
|
-
messenger.on(TagAction.DOC_CLICK, this.tagService.onActionDocClick.bind(this.tagService));
|
|
3449
|
-
messenger.on(TagAction.YOUTUBE_CLICK, this.tagService.onActionYoutubeClick.bind(this.tagService));
|
|
3450
|
-
}
|
|
3451
|
-
}
|
|
3452
|
-
else {
|
|
3453
|
-
// if html is empty (case of EMBED content), we edit billboard for Feature and attach new content
|
|
3454
|
-
const { comment, tagDescription } = this.tagService.getBillboardMediaToEmbed(object);
|
|
3455
|
-
if (comment) {
|
|
3456
|
-
// register the media
|
|
3457
|
-
const [attachmentID] = await this.sdk.Tag.registerAttachment(comment.externalLink);
|
|
3458
|
-
// attach
|
|
3459
|
-
this.sdk.Tag.attach(tagID, attachmentID);
|
|
3460
|
-
this.sdk.Tag.editBillboard(tagID, {
|
|
3461
|
-
label: object.title,
|
|
3462
|
-
description: tagDescription,
|
|
3463
|
-
});
|
|
3464
|
-
}
|
|
3465
|
-
}
|
|
4336
|
+
return this.matterportTagService.injectHtmlInTag(this.sdk, tagType, object, tagID);
|
|
3466
4337
|
}
|
|
3467
4338
|
async action_delete_all_mattertags() {
|
|
3468
|
-
await this.
|
|
3469
|
-
this.mattertagIDs = [];
|
|
3470
|
-
this.dictionnaryTags.clear();
|
|
4339
|
+
await this.matterportTagService.action_delete_all_mattertags(this.sdk);
|
|
3471
4340
|
}
|
|
3472
4341
|
/**
|
|
3473
4342
|
* Deletes Mattertag from visit associated with object ID (ticketID, etc)
|
|
@@ -3476,36 +4345,21 @@ class MatterportService {
|
|
|
3476
4345
|
async deleteMattertagForObject(elementID) {
|
|
3477
4346
|
const matterTagID = this.getTagFromElementId(elementID).tag;
|
|
3478
4347
|
if (matterTagID) {
|
|
3479
|
-
|
|
3480
|
-
await this.
|
|
3481
|
-
|
|
3482
|
-
const index = this.mattertagIDs.indexOf(matterTagID);
|
|
3483
|
-
this.mattertagIDs.splice(index, 1);
|
|
3484
|
-
}
|
|
3485
|
-
catch (error) {
|
|
3486
|
-
console.log('Cannot delete tag', matterTagID, error);
|
|
3487
|
-
}
|
|
4348
|
+
this.tagAddQueue = this.tagAddQueue.then(async () => {
|
|
4349
|
+
await this.matterportTagService.deleteMattertagFromId(this.sdk, matterTagID);
|
|
4350
|
+
});
|
|
3488
4351
|
}
|
|
4352
|
+
return this.tagAddQueue;
|
|
3489
4353
|
}
|
|
3490
4354
|
/**
|
|
3491
4355
|
* uuid from threejs
|
|
3492
4356
|
* @param uuid
|
|
3493
4357
|
*/
|
|
3494
4358
|
async deleteObject3D(uuid) {
|
|
3495
|
-
this.
|
|
4359
|
+
return this.object3DService.deleteObject3D(uuid);
|
|
3496
4360
|
}
|
|
3497
4361
|
getObject3DModelNodeFromDictionnary(uuid) {
|
|
3498
|
-
|
|
3499
|
-
if (!obj) {
|
|
3500
|
-
console.log("weird thing again");
|
|
3501
|
-
return null;
|
|
3502
|
-
}
|
|
3503
|
-
//might break things or fix everything ..?
|
|
3504
|
-
if (obj.obj3D.uuid != uuid) {
|
|
3505
|
-
console.log("we have THE problem");
|
|
3506
|
-
obj.obj3D.uuid = uuid; //not enugh to fix the pb
|
|
3507
|
-
}
|
|
3508
|
-
return obj;
|
|
4362
|
+
return this.object3DService.getObject3DModelNodeFromDictionnary(uuid);
|
|
3509
4363
|
}
|
|
3510
4364
|
/**
|
|
3511
4365
|
* Creates MattertagData and start repositioning (creates temporary mattertag that follows the cursor)
|
|
@@ -3546,10 +4400,10 @@ class MatterportService {
|
|
|
3546
4400
|
this.setInteractionMode(ViewerInteractions.DEFAULT);
|
|
3547
4401
|
}
|
|
3548
4402
|
setLastObject3D(lastObject3D) {
|
|
3549
|
-
this.lastObject3D = lastObject3D;
|
|
4403
|
+
this.object3DService.lastObject3D = lastObject3D;
|
|
3550
4404
|
}
|
|
3551
4405
|
getLastObject3D() {
|
|
3552
|
-
return this.lastObject3D;
|
|
4406
|
+
return this.object3DService.lastObject3D;
|
|
3553
4407
|
}
|
|
3554
4408
|
/**
|
|
3555
4409
|
* Performs callback after mattertag position was validated (creation of object or repositioning)
|
|
@@ -3645,7 +4499,6 @@ class MatterportService {
|
|
|
3645
4499
|
this.dictionnaryTags.get(mattertagID).elementID = object.id;
|
|
3646
4500
|
try {
|
|
3647
4501
|
await this.updateMatterTagContentForTagID(mattertagID, object, poiType);
|
|
3648
|
-
// TODO: fix this
|
|
3649
4502
|
await this.updateMatterTagPosInSdkViewer(mattertagID, object, poiType, poi);
|
|
3650
4503
|
}
|
|
3651
4504
|
catch (e) {
|
|
@@ -3669,7 +4522,7 @@ class MatterportService {
|
|
|
3669
4522
|
z: 0,
|
|
3670
4523
|
},
|
|
3671
4524
|
};
|
|
3672
|
-
this.sdk.Mattertag.editPosition(mattertagID, newPosition);
|
|
4525
|
+
//this.sdk.Mattertag.editPosition(mattertagID, newPosition);
|
|
3673
4526
|
this.sdk.Tag.editPosition(mattertagID, newPosition);
|
|
3674
4527
|
this.dictionnaryTags
|
|
3675
4528
|
.get(mattertagID)
|
|
@@ -3682,7 +4535,6 @@ class MatterportService {
|
|
|
3682
4535
|
if (currentTag.elementID === object.id && tagId !== mattertagID) {
|
|
3683
4536
|
this.dictionnaryTags.delete(tagId);
|
|
3684
4537
|
this.sdk.Tag.remove(tagId);
|
|
3685
|
-
this.sdk.Mattertag.remove(tagId);
|
|
3686
4538
|
break;
|
|
3687
4539
|
}
|
|
3688
4540
|
}
|
|
@@ -3692,19 +4544,8 @@ class MatterportService {
|
|
|
3692
4544
|
* @param elementID string
|
|
3693
4545
|
* @returns {tag: string | null, sweep: string | null}
|
|
3694
4546
|
*/
|
|
3695
|
-
getTagFromElementId(elementID) {
|
|
3696
|
-
|
|
3697
|
-
let sweepID = null;
|
|
3698
|
-
for (let [mattertagID, mattertagData] of this.dictionnaryTags) {
|
|
3699
|
-
if (mattertagData.elementID === elementID) {
|
|
3700
|
-
tagID = mattertagID;
|
|
3701
|
-
const sweep = mattertagData.getSweepID();
|
|
3702
|
-
if (sweep && this.sweeps && this.sweeps.includes(sweep)) {
|
|
3703
|
-
sweepID = sweep;
|
|
3704
|
-
}
|
|
3705
|
-
}
|
|
3706
|
-
}
|
|
3707
|
-
return { tag: tagID, sweep: sweepID };
|
|
4547
|
+
getTagFromElementId(elementID) {
|
|
4548
|
+
return this.matterportTagService.getTagFromElementId(elementID, this.sweeps);
|
|
3708
4549
|
}
|
|
3709
4550
|
/**
|
|
3710
4551
|
* Gets latest tag created in the visit (when following the cursor to position)
|
|
@@ -3738,42 +4579,16 @@ class MatterportService {
|
|
|
3738
4579
|
// ---------- Viewer related (switch views, go to) ----------
|
|
3739
4580
|
//
|
|
3740
4581
|
async action_toolbox_floorplan() {
|
|
3741
|
-
|
|
3742
|
-
console.log('viewer is in transition, cannot go floorplan');
|
|
3743
|
-
return;
|
|
3744
|
-
}
|
|
3745
|
-
try {
|
|
3746
|
-
await this.sdk.Mode.moveTo('mode.floorplan');
|
|
3747
|
-
}
|
|
3748
|
-
catch (e) {
|
|
3749
|
-
console.log('cannot go to floorplan', e);
|
|
3750
|
-
}
|
|
4582
|
+
return this.navigationService.action_toolbox_floorplan(this.sdk);
|
|
3751
4583
|
}
|
|
3752
4584
|
action_toolbox_inside_view() {
|
|
3753
|
-
this.
|
|
4585
|
+
this.navigationService.action_toolbox_inside_view(this.sdk);
|
|
3754
4586
|
}
|
|
3755
4587
|
actionShowAllFloors() {
|
|
3756
|
-
|
|
3757
|
-
this.sdk.Floor.showAll();
|
|
3758
|
-
}
|
|
3759
|
-
catch (e) {
|
|
3760
|
-
console.log('cannot show all floors', e);
|
|
3761
|
-
}
|
|
4588
|
+
this.navigationService.actionShowAllFloors(this.sdk);
|
|
3762
4589
|
}
|
|
3763
4590
|
async action_toolbox_dollhouse() {
|
|
3764
|
-
|
|
3765
|
-
// console.log("mode: ", this.inTransitionMode, " sweep: ", this.inTransitionSweep);
|
|
3766
|
-
if (this.inTransitionMode || this.inTransitionSweep) {
|
|
3767
|
-
console.log('viewer is in transition, cannot go dollhouse');
|
|
3768
|
-
return;
|
|
3769
|
-
}
|
|
3770
|
-
try {
|
|
3771
|
-
await this.sdk.Mode.moveTo('mode.dollhouse');
|
|
3772
|
-
}
|
|
3773
|
-
catch (e) {
|
|
3774
|
-
console.log('cannot go to dollhouse', e);
|
|
3775
|
-
}
|
|
3776
|
-
}, 1200);
|
|
4591
|
+
return this.navigationService.action_toolbox_dollhouse(this.sdk);
|
|
3777
4592
|
}
|
|
3778
4593
|
action_toolbox_mesure() {
|
|
3779
4594
|
const newState = !this.isMeasureModeOn;
|
|
@@ -3787,70 +4602,13 @@ class MatterportService {
|
|
|
3787
4602
|
}
|
|
3788
4603
|
}
|
|
3789
4604
|
async action_go_to_floor(floorName, matterportFloorSequence = null) {
|
|
3790
|
-
|
|
3791
|
-
console.log('Floor are not loaded yet');
|
|
3792
|
-
return;
|
|
3793
|
-
}
|
|
3794
|
-
// console.log(this.floors);
|
|
3795
|
-
// look up for sequence number (the safest method)
|
|
3796
|
-
let floorMatterport = this.floors.find((floor) => floor.sequence === matterportFloorSequence);
|
|
3797
|
-
if (!floorMatterport) {
|
|
3798
|
-
floorMatterport = this.floors.find((floor) => floorName.includes(floor.name) && floor.name != '');
|
|
3799
|
-
}
|
|
3800
|
-
if (!floorMatterport) {
|
|
3801
|
-
floorMatterport = this.floors.find((floor) => floorName.includes(floor.id));
|
|
3802
|
-
}
|
|
3803
|
-
// console.log(floorMatterport)
|
|
3804
|
-
if (floorMatterport) {
|
|
3805
|
-
let retry = true;
|
|
3806
|
-
while (retry) {
|
|
3807
|
-
try {
|
|
3808
|
-
const floorIndex = await this.sdk.Floor.moveTo(floorMatterport.sequence);
|
|
3809
|
-
// console.log("moved to floorIndex", floorIndex);
|
|
3810
|
-
retry = false;
|
|
3811
|
-
}
|
|
3812
|
-
catch (error) {
|
|
3813
|
-
console.log('Cannot move to Floor', error);
|
|
3814
|
-
await wait(100);
|
|
3815
|
-
}
|
|
3816
|
-
}
|
|
3817
|
-
}
|
|
3818
|
-
else {
|
|
3819
|
-
console.warn('No matterport floor found to move to');
|
|
3820
|
-
}
|
|
4605
|
+
return this.navigationService.action_go_to_floor(this.sdk, floorName, matterportFloorSequence);
|
|
3821
4606
|
}
|
|
3822
|
-
async action_go_to_sweep(sweep, rotation
|
|
3823
|
-
|
|
3824
|
-
console.log('user is not allowed to go to this sweep');
|
|
3825
|
-
return;
|
|
3826
|
-
}
|
|
3827
|
-
// console.log("going to sweep", sweep, "with rotation:", rotation);
|
|
3828
|
-
setTimeout(async () => {
|
|
3829
|
-
if (this.inTransitionMode || this.inTransitionSweep) {
|
|
3830
|
-
console.log('Cannot go to sweep, in transition');
|
|
3831
|
-
return;
|
|
3832
|
-
}
|
|
3833
|
-
try {
|
|
3834
|
-
this.inTransitionSweep = true;
|
|
3835
|
-
await this.sdk.Sweep.moveTo(sweep, {
|
|
3836
|
-
transition: 'transition.instant',
|
|
3837
|
-
transitionTime: 1500,
|
|
3838
|
-
});
|
|
3839
|
-
}
|
|
3840
|
-
catch (error) {
|
|
3841
|
-
this.inTransitionSweep = false;
|
|
3842
|
-
console.log('Cannot move to sweep', error);
|
|
3843
|
-
}
|
|
3844
|
-
if (rotation) {
|
|
3845
|
-
await this.sdk.Camera.setRotation(rotation, { speed: 100 }); // speed is degrees per second
|
|
3846
|
-
}
|
|
3847
|
-
}, 1000);
|
|
4607
|
+
async action_go_to_sweep(sweep, rotation) {
|
|
4608
|
+
return this.navigationService.action_go_to_sweep(this.sdk, sweep, rotation);
|
|
3848
4609
|
}
|
|
3849
4610
|
getCurrentSweep() {
|
|
3850
|
-
|
|
3851
|
-
return this.poseCamera.sweep;
|
|
3852
|
-
}
|
|
3853
|
-
return null;
|
|
4611
|
+
return this.navigationService.getCurrentSweep(this.poseCamera);
|
|
3854
4612
|
}
|
|
3855
4613
|
getCurrentCameraPosition() {
|
|
3856
4614
|
if (this.poseCamera) {
|
|
@@ -3869,341 +4627,54 @@ class MatterportService {
|
|
|
3869
4627
|
*/
|
|
3870
4628
|
async clearAll() {
|
|
3871
4629
|
console.log('removing viewer');
|
|
3872
|
-
this.action_delete_all_mattertags();
|
|
4630
|
+
await this.action_delete_all_mattertags();
|
|
3873
4631
|
this.floors = null;
|
|
3874
4632
|
this.sweeps = null;
|
|
3875
4633
|
this.sdk = null;
|
|
3876
|
-
|
|
4634
|
+
this.pointerService.clear({
|
|
4635
|
+
onLeftClick: this.pointerLeftClickHandler.bind(this),
|
|
4636
|
+
onRightClick: this.pointerRightClickHandler.bind(this),
|
|
4637
|
+
onMiddleClick: this.pointerMiddleClickHandler.bind(this),
|
|
4638
|
+
});
|
|
3877
4639
|
this.forbiddenSweeps = [];
|
|
3878
|
-
this.tagMessengerOn = false;
|
|
3879
|
-
// cancel subscriptions
|
|
3880
|
-
this.pointerButton.removeEventListener('click', this.pointerLeftClickHandler);
|
|
3881
|
-
this.pointerButton.removeEventListener('contextmenu', this.pointerRightClickHandler);
|
|
3882
|
-
// TODO: only For Admins
|
|
3883
|
-
if (this.getCursorPositionButton) {
|
|
3884
|
-
this.getCursorPositionButton.removeEventListener('auxclick', this.pointerMiddleClickHandler);
|
|
3885
|
-
}
|
|
3886
|
-
// TODO: only for dev!
|
|
3887
|
-
if (!!this.getCursorPositionButton &&
|
|
3888
|
-
(document.location.href.indexOf('dev') !== -1 || document.location.href.indexOf('localhost') !== -1)) {
|
|
3889
|
-
clearInterval(this.intervalCursorPointerPosition);
|
|
3890
|
-
}
|
|
3891
4640
|
}
|
|
3892
4641
|
async removeForbiddenSweeps(forbiddenSweeps) {
|
|
3893
|
-
this.
|
|
3894
|
-
let removed = 0;
|
|
3895
|
-
await Promise.all(forbiddenSweeps.map(async (sweep) => {
|
|
3896
|
-
try {
|
|
3897
|
-
await this.sdk.Sweep.disable(sweep);
|
|
3898
|
-
removed += 1;
|
|
3899
|
-
}
|
|
3900
|
-
catch (error) {
|
|
3901
|
-
console.log(error);
|
|
3902
|
-
}
|
|
3903
|
-
}));
|
|
3904
|
-
console.log('removed sweeps:', removed);
|
|
4642
|
+
return this.navigationService.removeForbiddenSweeps(this.sdk, forbiddenSweeps);
|
|
3905
4643
|
}
|
|
3906
4644
|
//
|
|
3907
4645
|
// ---------- 3D objects (SDK Bundle only) ----------
|
|
3908
4646
|
//
|
|
3909
4647
|
async init3DObjectViewer() {
|
|
3910
|
-
return
|
|
3911
|
-
var [sceneObject] = await this.sdk.Scene.createObjects(1);
|
|
3912
|
-
var node = sceneObject.addNode();
|
|
3913
|
-
// TODO change this 🤮
|
|
3914
|
-
node.addComponent('mp.lights');
|
|
3915
|
-
//node.addComponent('mp.lights');
|
|
3916
|
-
/*node.addComponent('mp.lights');
|
|
3917
|
-
node.addComponent('mp.lights');*/
|
|
3918
|
-
node.start();
|
|
3919
|
-
const nodeControl = sceneObject.addNode();
|
|
3920
|
-
this.objectControl = nodeControl.addComponent('mp.transformControls');
|
|
3921
|
-
nodeControl.start();
|
|
3922
|
-
//this.add3DObject({},null);
|
|
3923
|
-
resolve();
|
|
3924
|
-
});
|
|
4648
|
+
return this.object3DService.init3DObjectViewer(this.sdk);
|
|
3925
4649
|
}
|
|
3926
4650
|
async add3DObject(obj, mode) {
|
|
3927
|
-
return
|
|
3928
|
-
const [sceneObject] = await this.sdk.Scene.createObjects(1);
|
|
3929
|
-
// TODO: improvment, regroup all of these in Dynamical Objects Lib
|
|
3930
|
-
// SecurityCamera
|
|
3931
|
-
// NestThermostat
|
|
3932
|
-
// Video
|
|
3933
|
-
let isAnimatedSecurityCamera = false;
|
|
3934
|
-
let isNestThermostat = false;
|
|
3935
|
-
let isSmarterplanPromotionalVideo = false;
|
|
3936
|
-
let isAzimuthalCrown = false;
|
|
3937
|
-
/**
|
|
3938
|
-
* TODO: refacto with an enum or switch/case
|
|
3939
|
-
*/
|
|
3940
|
-
if (obj.object === "security_camera") {
|
|
3941
|
-
isAnimatedSecurityCamera = true;
|
|
3942
|
-
}
|
|
3943
|
-
if (obj.object === "nest_thermostat") {
|
|
3944
|
-
isNestThermostat = true;
|
|
3945
|
-
}
|
|
3946
|
-
if (obj.object === 'video') {
|
|
3947
|
-
isSmarterplanPromotionalVideo = true;
|
|
3948
|
-
}
|
|
3949
|
-
if (obj.object === 'azimuth') {
|
|
3950
|
-
isAzimuthalCrown = true;
|
|
3951
|
-
}
|
|
3952
|
-
const modelNode = sceneObject.addNode();
|
|
3953
|
-
let component = null;
|
|
3954
|
-
const initial = {
|
|
3955
|
-
url: `/assets/3Dobjects/objects/${obj.object}${obj.format.indexOf('.') === -1 ? '.' + obj.format : obj.format}`,
|
|
3956
|
-
// TODO/ store localPosition && localRotation in BDD too (in order to have pertfect initial placement)
|
|
3957
|
-
localRotation: { "x": 0, "y": 0, "z": 0 },
|
|
3958
|
-
// TODO/ store localPosition && localRotation in BDD too (in order to have pertfect initial placement)
|
|
3959
|
-
localPosition: { "x": 0, "y": 0, "z": 0 },
|
|
3960
|
-
visible: true,
|
|
3961
|
-
colliderEnabled: true
|
|
3962
|
-
};
|
|
3963
|
-
switch (obj.format) {
|
|
3964
|
-
case '.obj':
|
|
3965
|
-
case 'obj':
|
|
3966
|
-
component = modelNode.addComponent('mp.objLoader', initial);
|
|
3967
|
-
break;
|
|
3968
|
-
case '.fbx':
|
|
3969
|
-
case 'fbx':
|
|
3970
|
-
component = modelNode.addComponent('mp.fbxLoader', initial);
|
|
3971
|
-
break;
|
|
3972
|
-
case '.gltf':
|
|
3973
|
-
case 'gltf':
|
|
3974
|
-
component = modelNode.addComponent('mp.gltfLoader', initial);
|
|
3975
|
-
break;
|
|
3976
|
-
case '.glb':
|
|
3977
|
-
case 'glb':
|
|
3978
|
-
component = modelNode.addComponent('mp.gltfLoader', initial);
|
|
3979
|
-
break;
|
|
3980
|
-
case '.dae':
|
|
3981
|
-
case 'dae':
|
|
3982
|
-
component = modelNode.addComponent('mp.daeLoader', initial);
|
|
3983
|
-
break;
|
|
3984
|
-
default:
|
|
3985
|
-
console.log('Format not supported');
|
|
3986
|
-
break;
|
|
3987
|
-
}
|
|
3988
|
-
//cache system (i'll try to make it work later ...)
|
|
3989
|
-
/*let objContentsJSON = JSON.stringify(modelNode);
|
|
3990
|
-
console.log(modelNode);
|
|
3991
|
-
console.log(objContentsJSON);
|
|
3992
|
-
console.log(JSON.stringify(modelNode));
|
|
3993
|
-
localStorage.setItem(`testObj_${obj.object}`, objContentsJSON);
|
|
3994
|
-
console.log("stored ?!");
|
|
3995
|
-
console.log(typeof modelNode);*/
|
|
3996
|
-
//let dataS = serialijse.serialize(modelNode);
|
|
3997
|
-
//console.log(dataS);
|
|
3998
|
-
// Use 3 ?! Ambient lightings
|
|
3999
|
-
if (this.noLightForObjects) {
|
|
4000
|
-
const lightsNode = sceneObject.addNode();
|
|
4001
|
-
lightsNode.addComponent('mp.ambientLight', {
|
|
4002
|
-
intensity: 1,
|
|
4003
|
-
color: { r: 1.0, g: 1.0, b: 1.0 },
|
|
4004
|
-
});
|
|
4005
|
-
this.noLightForObjects = false;
|
|
4006
|
-
}
|
|
4007
|
-
modelNode.obj3D.position.set(obj.position.x, obj.position.y, obj.position.z);
|
|
4008
|
-
modelNode.obj3D.rotation.set(obj.rotation.x, obj.rotation.y, obj.rotation.z);
|
|
4009
|
-
modelNode.obj3D.scale.set(obj.scale.x, obj.scale.y, obj.scale.z);
|
|
4010
|
-
if (isAzimuthalCrown) {
|
|
4011
|
-
/*if(modelNode.obj3D.scale.x >= 1.0){
|
|
4012
|
-
modelNode.obj3D.scale.set(obj.scale.x/5000, obj.scale.y/5000, obj.scale.z/5000);
|
|
4013
|
-
}*/
|
|
4014
|
-
this.azimuthalCrown = modelNode;
|
|
4015
|
-
this.displayAzimutalCrown();
|
|
4016
|
-
}
|
|
4017
|
-
// By defaut, during creation, object has translation gizmo
|
|
4018
|
-
// => User has to click on lateral panel, and save its position after playing with it!
|
|
4019
|
-
if (mode && !isNestThermostat) {
|
|
4020
|
-
this.attachGizmoControlTo3DObject(modelNode, sceneObject, mode, true, true).catch((e) => console.log(e));
|
|
4021
|
-
}
|
|
4022
|
-
if (this.lastObject3D && typeof this.lastObject3D.id === 'string') {
|
|
4023
|
-
// prompt ThreeJS UUID to match our last generated object if new (not from Db)
|
|
4024
|
-
modelNode.obj3D.uuid = this.lastObject3D.id;
|
|
4025
|
-
}
|
|
4026
|
-
else if (obj.id) {
|
|
4027
|
-
modelNode.obj3D.uuid = obj.id;
|
|
4028
|
-
}
|
|
4029
|
-
this.lastObject3D = modelNode.obj3D;
|
|
4030
|
-
// Store this in memory Map dictionnary
|
|
4031
|
-
//console.log("Adding object: ");
|
|
4032
|
-
//console.log(modelNode);
|
|
4033
|
-
this.dictionnaryObjects3D.set(modelNode.obj3D.uuid, modelNode);
|
|
4034
|
-
this.dictionnarySceneObjects3D.set(modelNode.obj3D.uuid, sceneObject);
|
|
4035
|
-
/*this.sdk.Camera.pose.subscribe(
|
|
4036
|
-
function (pose: any) {
|
|
4037
|
-
//console.log("in callback")
|
|
4038
|
-
//console.log(this.lastCameraPosition)
|
|
4039
|
-
//console.log(pose.position)
|
|
4040
|
-
if((pose.position.x == this.lastCameraPosition.x && pose.position.y == this.lastCameraPosition.y && pose.position.z == this.lastCameraPosition.z) || this.inTransitionMode || this.inTransitionSweep){
|
|
4041
|
-
//console.log("returning")
|
|
4042
|
-
return;
|
|
4043
|
-
}
|
|
4044
|
-
console.log("camera pos:",pose.position);
|
|
4045
|
-
this.lastCameraPosition = {...pose.position};
|
|
4046
|
-
if(this.lastObject3D){
|
|
4047
|
-
this.lastObject3D.position.set(pose.position.x+.5,pose.position.y+.5,pose.position.z+.5);
|
|
4048
|
-
}
|
|
4049
|
-
}.bind(this));*/
|
|
4050
|
-
if (isAnimatedSecurityCamera) {
|
|
4051
|
-
const animator = modelNode.addComponent('mp.securityCamera', {
|
|
4052
|
-
"nearPlane": 0.1,
|
|
4053
|
-
"farPlane": 10,
|
|
4054
|
-
"horizontalFOV": 52,
|
|
4055
|
-
"aspect": 1.7777777777777777,
|
|
4056
|
-
"localPosition": {
|
|
4057
|
-
"x": 0.3,
|
|
4058
|
-
"y": 0.18,
|
|
4059
|
-
"z": 0
|
|
4060
|
-
},
|
|
4061
|
-
"localRotation": {
|
|
4062
|
-
"x": -15,
|
|
4063
|
-
"y": -90,
|
|
4064
|
-
"z": 0
|
|
4065
|
-
},
|
|
4066
|
-
"color": 65280,
|
|
4067
|
-
"panPeriod": 5,
|
|
4068
|
-
"panAngle": -45
|
|
4069
|
-
});
|
|
4070
|
-
const modelOutput = sceneObject.addPath({
|
|
4071
|
-
id: 'animated-model',
|
|
4072
|
-
type: this.sdk.Scene.PathType.OUTPUT,
|
|
4073
|
-
node: modelNode,
|
|
4074
|
-
component: animator,
|
|
4075
|
-
property: 'objectRoot'
|
|
4076
|
-
});
|
|
4077
|
-
this.securityCameraAnimator = animator;
|
|
4078
|
-
if (!obj.viewFrustum) {
|
|
4079
|
-
setTimeout(() => {
|
|
4080
|
-
animator.toggleViewFrustum();
|
|
4081
|
-
}, 1000);
|
|
4082
|
-
}
|
|
4083
|
-
}
|
|
4084
|
-
if (isNestThermostat) {
|
|
4085
|
-
// TODO: use bindPath instead using MP sdk classes (see Security Camera example)
|
|
4086
|
-
// for TV uses CanvasImage below!
|
|
4087
|
-
// const ci = new CanvasImage();
|
|
4088
|
-
// ci.onInit();
|
|
4089
|
-
const cv = new CanvasRenderer();
|
|
4090
|
-
cv.onInit();
|
|
4091
|
-
const plane = new PlaneRenderer();
|
|
4092
|
-
plane.outputs = {
|
|
4093
|
-
objectRoot: new Object3D(),
|
|
4094
|
-
collider: new Object3D()
|
|
4095
|
-
};
|
|
4096
|
-
const inputTexture = cv.outputs.texture;
|
|
4097
|
-
plane.setRootScene(this.threeJSScene);
|
|
4098
|
-
plane.onInit(modelNode, inputTexture);
|
|
4099
|
-
const sc = new NestThermostat();
|
|
4100
|
-
sc.setComponent(component, plane, cv);
|
|
4101
|
-
sc.setRootScene(this.threeJSScene);
|
|
4102
|
-
sc.onInit(modelNode, plane, inputTexture);
|
|
4103
|
-
cv.setCanvasNestThermostatPainter(sc);
|
|
4104
|
-
setTimeout(() => {
|
|
4105
|
-
sc.inputs.loadingState = "Loaded";
|
|
4106
|
-
sc.onInputsUpdated();
|
|
4107
|
-
}, 5000);
|
|
4108
|
-
}
|
|
4109
|
-
if (isSmarterplanPromotionalVideo) {
|
|
4110
|
-
// TODO: use bindPath instead using MP sdk classes (see Security Camera example)
|
|
4111
|
-
const sc = new TvPlayer();
|
|
4112
|
-
sc.setComponent(component);
|
|
4113
|
-
sc.onInit(modelNode);
|
|
4114
|
-
setTimeout(() => {
|
|
4115
|
-
sc.inputs.loadingState = "Loaded";
|
|
4116
|
-
sc.onInputsUpdated();
|
|
4117
|
-
}, 5000);
|
|
4118
|
-
}
|
|
4119
|
-
sceneObject.start();
|
|
4120
|
-
resolve(this.lastObject3D);
|
|
4121
|
-
});
|
|
4651
|
+
return this.object3DService.add3DObject(this.sdk, obj, mode);
|
|
4122
4652
|
}
|
|
4123
4653
|
toggleObjectVisibility(objectId) {
|
|
4124
|
-
|
|
4125
|
-
obj.obj3D.visible = !obj.obj3D.visible;
|
|
4654
|
+
this.object3DService.toggleObjectVisibility(objectId);
|
|
4126
4655
|
}
|
|
4127
4656
|
isObjectVisible(objectId) {
|
|
4128
|
-
|
|
4129
|
-
return obj.obj3D.visible;
|
|
4657
|
+
return this.object3DService.isObjectVisible(objectId);
|
|
4130
4658
|
}
|
|
4131
4659
|
async pointCameraTo3DObject(objectId) {
|
|
4132
|
-
|
|
4133
|
-
//We create a temporary Tag
|
|
4134
|
-
const poiObject = {
|
|
4135
|
-
coordinate: JSON.stringify(obj.obj3D.position),
|
|
4136
|
-
type: PoiType.OBJECT3D,
|
|
4137
|
-
elementID: objectId, //todo: be careful with this
|
|
4138
|
-
};
|
|
4139
|
-
const objectDb = { id: objectId };
|
|
4140
|
-
try {
|
|
4141
|
-
await this.createMattertagFromPOI(PoiType.OBJECT3D, objectDb, poiObject);
|
|
4142
|
-
}
|
|
4143
|
-
catch (err) { }
|
|
4144
|
-
//Not really necessary anymore since the tag will disappear quick
|
|
4145
|
-
//this.sdk.Tag.editOpacity(mattertagID, 0.0);//opacity);
|
|
4146
|
-
//this.sdk.Tag.allowAction(mattertagID, {}); //disables every action
|
|
4147
|
-
let result = this.getTagFromElementId(objectId);
|
|
4148
|
-
await this.goToTag(result.tag);
|
|
4149
|
-
this.deleteLastMattertag();
|
|
4660
|
+
return this.object3DService.pointCameraTo3DObject(this.sdk, objectId, this.createMattertagFromPOI.bind(this), this.goToTag.bind(this), this.deleteLastMattertag.bind(this), this.getTagFromElementId.bind(this));
|
|
4150
4661
|
}
|
|
4151
4662
|
getSceneNodeFromObject3DId(uuid) {
|
|
4152
|
-
return this.
|
|
4663
|
+
return this.object3DService.getSceneNodeFromObject3DId(uuid);
|
|
4153
4664
|
}
|
|
4154
4665
|
async displayAzimutalCrown() {
|
|
4155
|
-
|
|
4156
|
-
this.azimuthalCrown.obj3D.position.set(this.poseCamera.position.x, this.poseCamera.position.y, this.poseCamera.position.z);
|
|
4157
|
-
}
|
|
4666
|
+
return this.object3DService.displayAzimutalCrown(this.poseCamera);
|
|
4158
4667
|
}
|
|
4159
4668
|
async attachGizmoControlTo3DObject(modelNode, sceneObject, mode, visible, isNewObject) {
|
|
4160
|
-
|
|
4161
|
-
let node = null;
|
|
4162
|
-
node = sceneObject.addNode();
|
|
4163
|
-
if (!node) {
|
|
4164
|
-
const [sceneObject] = await this.sdk.Scene.createObjects(1);
|
|
4165
|
-
node = sceneObject.addNode();
|
|
4166
|
-
}
|
|
4167
|
-
const myControl = node.addComponent('mp.transformControls');
|
|
4168
|
-
node.start();
|
|
4169
|
-
//
|
|
4170
|
-
// // Make the transform control visible so that the user can manipulate the control selection.
|
|
4171
|
-
myControl.transformControls.visible = visible;
|
|
4172
|
-
//
|
|
4173
|
-
// // Attach the model to the transform control
|
|
4174
|
-
myControl.inputs.selection = modelNode;
|
|
4175
|
-
//
|
|
4176
|
-
// // set 'translate' mode to position the selection.
|
|
4177
|
-
myControl.inputs.mode = mode;
|
|
4178
|
-
modelNode.obj3D.controls = myControl; // store gizmoCtrl inside object
|
|
4179
|
-
if (isNewObject) { //i keep the current solution for new objects
|
|
4180
|
-
if (!this.lastObject3D || !this.lastObject3D.controls) {
|
|
4181
|
-
try {
|
|
4182
|
-
modelNode.obj3D.uuid = this.lastObject3D.uuid || this.lastObject3D.id;
|
|
4183
|
-
}
|
|
4184
|
-
catch (e) {
|
|
4185
|
-
console.log(`id obj in Scene was not assigned to id from DB since`);
|
|
4186
|
-
}
|
|
4187
|
-
this.lastObject3D = modelNode.obj3D;
|
|
4188
|
-
}
|
|
4189
|
-
}
|
|
4190
|
-
else { //objects already in place have to become the "lastObject" (i think?)
|
|
4191
|
-
console.log("in my solution !");
|
|
4192
|
-
console.log(modelNode);
|
|
4193
|
-
console.log(modelNode.obj3D.uuid);
|
|
4194
|
-
this.lastObject3D = modelNode.obj3D;
|
|
4195
|
-
}
|
|
4196
|
-
return modelNode;
|
|
4669
|
+
return this.object3DService.attachGizmoControlTo3DObject(this.sdk, modelNode, sceneObject, mode, visible, isNewObject);
|
|
4197
4670
|
}
|
|
4198
4671
|
removeGizmoFromLastObject() {
|
|
4199
|
-
this.
|
|
4200
|
-
this.lastObject3D.controls.transformControls.dispose();
|
|
4201
|
-
this.lastObject3D.controls = null;
|
|
4672
|
+
this.object3DService.removeGizmoFromLastObject();
|
|
4202
4673
|
}
|
|
4203
4674
|
toggleViewFrustum() {
|
|
4204
|
-
this.
|
|
4675
|
+
this.object3DService.toggleViewFrustum();
|
|
4205
4676
|
}
|
|
4206
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportService, deps: [{ token: 'config' }, { token: i1$1.Router }, { token: i1$1.ActivatedRoute }, { token: BaseVisibilityService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
4677
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportService, deps: [{ token: 'config' }, { token: i1$1.Router }, { token: i1$1.ActivatedRoute }, { token: BaseVisibilityService }, { token: i0.NgZone }, { token: MatterportMeasurementService }, { token: MatterportNavigationService }, { token: MatterportPointerService }, { token: MatterportObject3DService }, { token: MatterportTagService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
4207
4678
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportService, providedIn: 'root' });
|
|
4208
4679
|
}
|
|
4209
4680
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportService, decorators: [{
|
|
@@ -4214,7 +4685,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
4214
4685
|
}], ctorParameters: () => [{ type: Config, decorators: [{
|
|
4215
4686
|
type: Inject,
|
|
4216
4687
|
args: ['config']
|
|
4217
|
-
}] }, { type: i1$1.Router }, { type: i1$1.ActivatedRoute }, { type: BaseVisibilityService }, { type: i0.NgZone }] });
|
|
4688
|
+
}] }, { type: i1$1.Router }, { type: i1$1.ActivatedRoute }, { type: BaseVisibilityService }, { type: i0.NgZone }, { type: MatterportMeasurementService }, { type: MatterportNavigationService }, { type: MatterportPointerService }, { type: MatterportObject3DService }, { type: MatterportTagService }] });
|
|
4218
4689
|
|
|
4219
4690
|
/* eslint-disable no-await-in-loop */
|
|
4220
4691
|
/* eslint-disable camelcase */
|
|
@@ -4275,21 +4746,50 @@ class ViewerService {
|
|
|
4275
4746
|
setMode(indexMode) {
|
|
4276
4747
|
this.viewerMode = indexMode;
|
|
4277
4748
|
}
|
|
4278
|
-
setTourUrl(model3d, showIconPlan = true, showIconDollhouse = true, showIconFloors = true,
|
|
4279
|
-
|
|
4280
|
-
|
|
4749
|
+
setTourUrl(model3d, showIconPlan = true, showIconDollhouse = true, showIconFloors = true, showQuickStart = true, showFullscreen = true, showGuidedTour = true, showHighlightReel = true) {
|
|
4750
|
+
const baseUrl = `/assets/bundle/showcase.html`;
|
|
4751
|
+
const params = [];
|
|
4752
|
+
// Modèle
|
|
4753
|
+
params.push(`m=${model3d}`);
|
|
4754
|
+
// Comportement général
|
|
4755
|
+
params.push(`play=1`);
|
|
4756
|
+
params.push(`ui=1`);
|
|
4757
|
+
params.push(`title=0`);
|
|
4758
|
+
params.push(`log=0`);
|
|
4759
|
+
params.push(`brand=0`);
|
|
4760
|
+
params.push(`search=0`);
|
|
4761
|
+
params.push(`applicationKey=qn9wsasuy5h2fzrbrn1nzr0id`);
|
|
4762
|
+
params.push(`mds=0`);
|
|
4763
|
+
// Quick start
|
|
4764
|
+
if (showQuickStart) {
|
|
4765
|
+
params.push(`qs=1`);
|
|
4766
|
+
}
|
|
4767
|
+
// Floorplan (plan)
|
|
4281
4768
|
if (!showIconPlan) {
|
|
4282
|
-
|
|
4769
|
+
params.push(`fp=0`);
|
|
4283
4770
|
}
|
|
4771
|
+
// Dollhouse (maison/poupée)
|
|
4284
4772
|
if (!showIconDollhouse) {
|
|
4285
|
-
|
|
4773
|
+
params.push(`dh=0`);
|
|
4286
4774
|
}
|
|
4775
|
+
// Sélecteur d’étages
|
|
4287
4776
|
if (!showIconFloors) {
|
|
4288
|
-
|
|
4777
|
+
params.push(`sf=0`);
|
|
4778
|
+
}
|
|
4779
|
+
// Guided tour
|
|
4780
|
+
if (!showGuidedTour) {
|
|
4781
|
+
params.push(`gt=0`);
|
|
4289
4782
|
}
|
|
4290
|
-
|
|
4291
|
-
|
|
4783
|
+
// Highlight reel (bande du bas)
|
|
4784
|
+
if (!showHighlightReel) {
|
|
4785
|
+
// Selon ton bundle : hr=1 ou hr=0 masque
|
|
4786
|
+
params.push(`hr=1`);
|
|
4292
4787
|
}
|
|
4788
|
+
// Plein écran
|
|
4789
|
+
if (!showFullscreen) {
|
|
4790
|
+
params.push(`fs=0`);
|
|
4791
|
+
}
|
|
4792
|
+
this.tourUrl = `${baseUrl}?${params.join("&")}`;
|
|
4293
4793
|
}
|
|
4294
4794
|
async clearAll() {
|
|
4295
4795
|
// this.sweepToMove = null;
|
|
@@ -4552,19 +5052,15 @@ class ViewerService {
|
|
|
4552
5052
|
.then(async (result) => {
|
|
4553
5053
|
if (result) {
|
|
4554
5054
|
const { sdk } = this.matterportService;
|
|
4555
|
-
// TODO: add condition whether we want to enable it or not
|
|
4556
|
-
// Additionnal extensions for Matterport
|
|
4557
|
-
// 1. Security Camera with Frustum (FOV)
|
|
4558
|
-
// 2. TODO register all new Matterport extensions here (nestSensor, lods, slots, ...)
|
|
4559
5055
|
await Promise.all([
|
|
4560
5056
|
sdk.Scene.register(securityCameraType, makeSecurityCamera.bind(sdk.Scene)),
|
|
4561
5057
|
sdk.Scene.register(ViewFrustumMeshType, makeViewFrustumMesh.bind(sdk.Scene))
|
|
4562
5058
|
]);
|
|
5059
|
+
this.showingViewer = true;
|
|
4563
5060
|
sdk.App.state.subscribe(function (appState) {
|
|
4564
|
-
|
|
4565
|
-
// console.log('The current phase: ', appState.phase);
|
|
5061
|
+
console.debug('The current phase: ', appState.phase);
|
|
4566
5062
|
if (appState.phase === sdk.App.Phase.PLAYING) {
|
|
4567
|
-
|
|
5063
|
+
console.log('The app is playing');
|
|
4568
5064
|
this.showingViewer = true;
|
|
4569
5065
|
this.viewerIsOn.next({
|
|
4570
5066
|
spaceID,
|
|
@@ -4578,6 +5074,16 @@ class ViewerService {
|
|
|
4578
5074
|
this.rotationToMove = null;
|
|
4579
5075
|
}
|
|
4580
5076
|
}.bind(this));
|
|
5077
|
+
this.viewerIsOn.next({
|
|
5078
|
+
spaceID,
|
|
5079
|
+
model3D,
|
|
5080
|
+
sweep: this.sweepToMove,
|
|
5081
|
+
rotation: this.rotationToMove,
|
|
5082
|
+
});
|
|
5083
|
+
this.dataIsLoaded.next(true);
|
|
5084
|
+
this.isLoaded = true;
|
|
5085
|
+
this.sweepToMove = null;
|
|
5086
|
+
this.rotationToMove = null;
|
|
4581
5087
|
return Promise.resolve();
|
|
4582
5088
|
}
|
|
4583
5089
|
return Promise.reject();
|
|
@@ -5012,6 +5518,23 @@ function openModalForVisitSwitch(modalService, model3D, spaceID, dataToMove = nu
|
|
|
5012
5518
|
modalReference.componentInstance.dataToMove = dataToMove;
|
|
5013
5519
|
}
|
|
5014
5520
|
}
|
|
5521
|
+
function getCurrentLang(translate) {
|
|
5522
|
+
let lang = translate.getCurrentLang() || translate.getFallbackLang() || "fr";
|
|
5523
|
+
// Clean up leading mess
|
|
5524
|
+
lang = lang.replace(/^[_-]+/, '');
|
|
5525
|
+
// Handle fr_FR or fr-FR (take primary language)
|
|
5526
|
+
if (lang.includes("_")) {
|
|
5527
|
+
lang = lang.split("_")[0];
|
|
5528
|
+
}
|
|
5529
|
+
if (lang.includes("-")) {
|
|
5530
|
+
lang = lang.split("-")[0];
|
|
5531
|
+
}
|
|
5532
|
+
// Ensure 2-letter code (ISO 639-1)
|
|
5533
|
+
if (lang.length > 2) {
|
|
5534
|
+
lang = lang.substring(0, 2);
|
|
5535
|
+
}
|
|
5536
|
+
return lang;
|
|
5537
|
+
}
|
|
5015
5538
|
/**
|
|
5016
5539
|
* Return a string of a given date time in local format.
|
|
5017
5540
|
* The format is determined by the current language.
|
|
@@ -5019,14 +5542,7 @@ function openModalForVisitSwitch(modalService, model3D, spaceID, dataToMove = nu
|
|
|
5019
5542
|
function dateTimeToLocalString(date, translate, mode) {
|
|
5020
5543
|
let lang = "en-EN";
|
|
5021
5544
|
if (translate) {
|
|
5022
|
-
|
|
5023
|
-
lang = translate.currentLang
|
|
5024
|
-
? translate.currentLang
|
|
5025
|
-
: translate.defaultLang;
|
|
5026
|
-
/** Transforme '_fr' to 'fr' */
|
|
5027
|
-
if (lang) {
|
|
5028
|
-
lang = lang.slice(1);
|
|
5029
|
-
}
|
|
5545
|
+
lang = getCurrentLang(translate);
|
|
5030
5546
|
}
|
|
5031
5547
|
let options;
|
|
5032
5548
|
switch (mode) {
|
|
@@ -5155,11 +5671,7 @@ function translateDatePeriod(translateService, dateStartPeriod, dateEndPeriod) {
|
|
|
5155
5671
|
* Return local in the canonical form: "en-GB", "fr-FR"
|
|
5156
5672
|
*/
|
|
5157
5673
|
function getLocaleLong(translate) {
|
|
5158
|
-
let lang = translate
|
|
5159
|
-
? translate.currentLang
|
|
5160
|
-
: translate.defaultLang;
|
|
5161
|
-
/** Transform '_fr' to 'fr' */
|
|
5162
|
-
lang = lang.slice(1);
|
|
5674
|
+
let lang = getCurrentLang(translate);
|
|
5163
5675
|
if (lang === "en") {
|
|
5164
5676
|
return "en-GB";
|
|
5165
5677
|
}
|
|
@@ -5169,12 +5681,7 @@ function getLocaleLong(translate) {
|
|
|
5169
5681
|
* Return local in the short form: "en", "fr"
|
|
5170
5682
|
*/
|
|
5171
5683
|
function getLocaleShort(translate) {
|
|
5172
|
-
|
|
5173
|
-
? translate.currentLang
|
|
5174
|
-
: translate.defaultLang;
|
|
5175
|
-
/** Transform '_fr' to 'fr' */
|
|
5176
|
-
lang = lang.slice(1);
|
|
5177
|
-
return lang;
|
|
5684
|
+
return getCurrentLang(translate);
|
|
5178
5685
|
}
|
|
5179
5686
|
/**
|
|
5180
5687
|
* Format string to lowercase, no spaces
|
|
@@ -5243,6 +5750,12 @@ function durationToString(duration, translate) {
|
|
|
5243
5750
|
}
|
|
5244
5751
|
return `${seconds} ${secondsString}`;
|
|
5245
5752
|
}
|
|
5753
|
+
function pointToString(point) {
|
|
5754
|
+
const x = point.x.toFixed(3);
|
|
5755
|
+
const y = point.y.toFixed(3);
|
|
5756
|
+
const z = point.z.toFixed(3);
|
|
5757
|
+
return `{ x: ${x}, y: ${y}, z: ${z} }`;
|
|
5758
|
+
}
|
|
5246
5759
|
|
|
5247
5760
|
/* eslint-disable class-methods-use-this */
|
|
5248
5761
|
class ZoneService {
|
|
@@ -6635,6 +7148,11 @@ class NavigatorService {
|
|
|
6635
7148
|
// if first load and zones are not set
|
|
6636
7149
|
this.zonesForUserForSpace = await this.zoneService.getZonesBySpaceForUser(this.currentSpaceID);
|
|
6637
7150
|
this.audioZonesForUserForSpace = this.zonesForUserForSpace.filter((zone) => zone.audioID);
|
|
7151
|
+
this.zonesForUserForSpace = await this.zoneService.getZonesBySpaceForUser(this.currentSpaceID);
|
|
7152
|
+
this.audioZonesForUserForSpace = this.zonesForUserForSpace.filter((zone) => zone.audioID);
|
|
7153
|
+
if (!this.currentSweep) {
|
|
7154
|
+
this.currentSweep = this.matterportService.getCurrentSweep();
|
|
7155
|
+
}
|
|
6638
7156
|
this.setZonesForCurrentSweep();
|
|
6639
7157
|
}
|
|
6640
7158
|
checkRotationForSweep(sweep) {
|
|
@@ -6648,7 +7166,10 @@ class NavigatorService {
|
|
|
6648
7166
|
if (!this.currentSweep) {
|
|
6649
7167
|
return;
|
|
6650
7168
|
}
|
|
6651
|
-
|
|
7169
|
+
const uuid = this.matterportService.getSweepUUIDForSid(this.currentSweep);
|
|
7170
|
+
console.log('uuid', uuid);
|
|
7171
|
+
const sweepToMatch = uuid ?? this.currentSweep;
|
|
7172
|
+
let zonesForSweep = this.zonesForUserForSpace?.filter((zone) => zone.sweepIDs && zone.sweepIDs.includes(sweepToMatch));
|
|
6652
7173
|
const audioZones = this.audioZonesForUserForSpace?.filter((zone) => zone.sweepIDs && zone.sweepIDs.includes(this.currentSweep));
|
|
6653
7174
|
this.audioZonesChange.next(audioZones);
|
|
6654
7175
|
this.currentAudioZones = audioZones;
|
|
@@ -6939,7 +7460,7 @@ class TicketsService extends BaseObjectService {
|
|
|
6939
7460
|
zone: [],
|
|
6940
7461
|
space: [],
|
|
6941
7462
|
};
|
|
6942
|
-
ticketTags = new
|
|
7463
|
+
ticketTags = new BehaviorSubject(null);
|
|
6943
7464
|
ticketsFiltered = [];
|
|
6944
7465
|
ticketsUpdated = new Subject();
|
|
6945
7466
|
currentSpaceID;
|
|
@@ -7391,7 +7912,6 @@ class TicketsService extends BaseObjectService {
|
|
|
7391
7912
|
}
|
|
7392
7913
|
}
|
|
7393
7914
|
else {
|
|
7394
|
-
/** Si on force le switch de la visit */
|
|
7395
7915
|
window.open(`${url}?model3D=${result.model3D}&sweep=true`, '_blank');
|
|
7396
7916
|
}
|
|
7397
7917
|
}
|
|
@@ -7465,7 +7985,7 @@ class EquipmentService extends BaseObjectService {
|
|
|
7465
7985
|
space: [],
|
|
7466
7986
|
zonesMap: new Map(),
|
|
7467
7987
|
};
|
|
7468
|
-
equipmentsTags = new
|
|
7988
|
+
equipmentsTags = new BehaviorSubject(null);
|
|
7469
7989
|
zoneIDFilter;
|
|
7470
7990
|
currentZone;
|
|
7471
7991
|
currentSpaceID;
|
|
@@ -7942,7 +8462,6 @@ class EquipmentService extends BaseObjectService {
|
|
|
7942
8462
|
}
|
|
7943
8463
|
}
|
|
7944
8464
|
else {
|
|
7945
|
-
/** Si on force le switch de la visit */
|
|
7946
8465
|
window.open(`${url}?model3D=${result.model3D}&sweep=true`, '_blank');
|
|
7947
8466
|
}
|
|
7948
8467
|
}
|
|
@@ -8461,13 +8980,8 @@ class TimeDateToLocalStringPipe {
|
|
|
8461
8980
|
let lang = "en-EN";
|
|
8462
8981
|
if (this.translate) {
|
|
8463
8982
|
/** Get current language */
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
: this.translate.getFallbackLang();
|
|
8467
|
-
/** Transforme '_fr' to 'fr' */
|
|
8468
|
-
if (lang) {
|
|
8469
|
-
lang = lang.slice(1);
|
|
8470
|
-
}
|
|
8983
|
+
const currentLang = this.translate.getCurrentLang() || this.translate.getFallbackLang() || "fr";
|
|
8984
|
+
lang = currentLang.replace(/^[_-]+/, '').substring(0, 2);
|
|
8471
8985
|
}
|
|
8472
8986
|
let options;
|
|
8473
8987
|
switch (mode) {
|
|
@@ -8802,10 +9316,8 @@ class LocaleService {
|
|
|
8802
9316
|
this.translate.use(`_${lang}`); // because files are "_en.json"
|
|
8803
9317
|
}
|
|
8804
9318
|
getLocale() {
|
|
8805
|
-
const
|
|
8806
|
-
|
|
8807
|
-
: this.translate.getFallbackLang();
|
|
8808
|
-
return lang.slice(1);
|
|
9319
|
+
const currentLang = this.translate.getCurrentLang() || this.translate.getFallbackLang() || "fr";
|
|
9320
|
+
return currentLang.replace(/^[_-]+/, '').substring(0, 2);
|
|
8809
9321
|
}
|
|
8810
9322
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LocaleService, deps: [{ token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
8811
9323
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LocaleService, providedIn: "root" });
|
|
@@ -10278,7 +10790,7 @@ class FeatureService extends BaseObjectService {
|
|
|
10278
10790
|
space: [],
|
|
10279
10791
|
zone: [],
|
|
10280
10792
|
};
|
|
10281
|
-
featureTags = new
|
|
10793
|
+
featureTags = new BehaviorSubject(null);
|
|
10282
10794
|
featureFiltered = [];
|
|
10283
10795
|
updateDone = new Subject();
|
|
10284
10796
|
zoneIDFilter;
|
|
@@ -10649,7 +11161,7 @@ class MeasurementService {
|
|
|
10649
11161
|
navigationService;
|
|
10650
11162
|
path = 'measurements/';
|
|
10651
11163
|
currentMeasurements = { space: [], zone: [] };
|
|
10652
|
-
measurementsTags = new
|
|
11164
|
+
measurementsTags = new BehaviorSubject(null);
|
|
10653
11165
|
measurementsUpdated = new Subject();
|
|
10654
11166
|
currentSpaceID;
|
|
10655
11167
|
zoneIDFilter;
|
|
@@ -11804,10 +12316,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
11804
12316
|
/* eslint-disable class-methods-use-this */
|
|
11805
12317
|
class BaseTagService {
|
|
11806
12318
|
constructor() { }
|
|
12319
|
+
/** Base implementation for generating tag HTML. Override in derived classes. */
|
|
11807
12320
|
async getHtmlToInject(tagType, object) {
|
|
11808
|
-
|
|
11809
|
-
|
|
12321
|
+
return "";
|
|
12322
|
+
}
|
|
12323
|
+
/** Base implementation for injecting HTML into a tag container. */
|
|
12324
|
+
async injectHtml(container, tagType, object) {
|
|
12325
|
+
if (!container) {
|
|
12326
|
+
console.warn('injectHtml: container is null');
|
|
12327
|
+
return;
|
|
12328
|
+
}
|
|
12329
|
+
try {
|
|
12330
|
+
const html = await this.getHtmlToInject(tagType, object);
|
|
12331
|
+
if (!html || html.trim().length === 0) {
|
|
12332
|
+
console.warn(`Empty HTML returned for ${tagType}`);
|
|
12333
|
+
container.innerHTML = `<div class="tag-div" style="color: white; padding: 10px;">Base implementation: No content for ${tagType}</div>`;
|
|
12334
|
+
}
|
|
12335
|
+
else {
|
|
12336
|
+
container.innerHTML = html;
|
|
12337
|
+
}
|
|
12338
|
+
}
|
|
12339
|
+
catch (error) {
|
|
12340
|
+
console.error('Error in injectHtml:', error);
|
|
12341
|
+
container.innerHTML = `<div class="tag-div" style="color: white; padding: 10px;">Error: ${error.message}</div>`;
|
|
12342
|
+
}
|
|
11810
12343
|
}
|
|
12344
|
+
/** Returns the navigation URL for viewing details of a specific object type. */
|
|
11811
12345
|
getUrlForSeeDetails(object, tagType) {
|
|
11812
12346
|
switch (tagType) {
|
|
11813
12347
|
case PoiType.TICKET: {
|
|
@@ -11829,28 +12363,31 @@ class BaseTagService {
|
|
|
11829
12363
|
return '';
|
|
11830
12364
|
}
|
|
11831
12365
|
}
|
|
12366
|
+
/*async updatePoiMetadata(poiId: string, metadata: string): Promise<void> {
|
|
12367
|
+
throw new Error('updatePoiMetadata is not implemented in the base class.');
|
|
12368
|
+
}*/
|
|
11832
12369
|
async prepareEquipmentHtml(equip) {
|
|
11833
|
-
throw new Error(`prepareEquipmentHtml is not implemented in the base class.
|
|
12370
|
+
throw new Error(`prepareEquipmentHtml is not implemented in the base class.
|
|
11834
12371
|
Please override this method in your extended class.`);
|
|
11835
12372
|
}
|
|
11836
12373
|
async prepareTicketHtml(ticket) {
|
|
11837
|
-
throw new Error(`prepareTicketHtml is not implemented in the base class.
|
|
12374
|
+
throw new Error(`prepareTicketHtml is not implemented in the base class.
|
|
11838
12375
|
Please override this method in your extended class.`);
|
|
11839
12376
|
}
|
|
11840
12377
|
async prepareFeatureHtml(feature) {
|
|
11841
|
-
throw new Error(`prepareFeatureHtml is not implemented in the base class.
|
|
12378
|
+
throw new Error(`prepareFeatureHtml is not implemented in the base class.
|
|
11842
12379
|
Please override this method in your extended class.`);
|
|
11843
12380
|
}
|
|
11844
12381
|
async prepareMeasurementHtml(measure) {
|
|
11845
|
-
throw new Error(`prepareMeasurementHtml is not implemented in the base class.
|
|
12382
|
+
throw new Error(`prepareMeasurementHtml is not implemented in the base class.
|
|
11846
12383
|
Please override this method in your extended class.`);
|
|
11847
12384
|
}
|
|
11848
12385
|
async prepareDeskHtml(feature) {
|
|
11849
|
-
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
12386
|
+
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
11850
12387
|
Please override this method in your extended class.`);
|
|
11851
12388
|
}
|
|
11852
12389
|
async prepareIndicatorHtml(feature) {
|
|
11853
|
-
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
12390
|
+
throw new Error(`prepareDeskHtml is not implemented in the base class.
|
|
11854
12391
|
Please override this method in your extended class.`);
|
|
11855
12392
|
}
|
|
11856
12393
|
async getSignedTagIconSource(tagIconSrc) {
|
|
@@ -11859,31 +12396,32 @@ class BaseTagService {
|
|
|
11859
12396
|
getIconTagImageForFeature(feature, poi) {
|
|
11860
12397
|
// const tagIcon = JSON.parse(poi.tagIcon);
|
|
11861
12398
|
// return tagIcon.src;
|
|
11862
|
-
throw new Error(`getIconTagImageForFeature is not implemented in the base class.
|
|
12399
|
+
throw new Error(`getIconTagImageForFeature is not implemented in the base class.
|
|
11863
12400
|
Please override this method in your extended class.`);
|
|
11864
12401
|
}
|
|
11865
12402
|
getScriptForTag(object, tagType) {
|
|
11866
|
-
throw new Error(`getScriptForTag is not implemented in the base class.
|
|
12403
|
+
throw new Error(`getScriptForTag is not implemented in the base class.
|
|
11867
12404
|
Please override this method in your extended class.`);
|
|
11868
12405
|
}
|
|
11869
12406
|
getAnnexeForCommentTypeInFeature(feature, commentType) {
|
|
11870
|
-
throw new Error(`getAnnexeForCommentTypeInFeature is not implemented in the base class.
|
|
12407
|
+
throw new Error(`getAnnexeForCommentTypeInFeature is not implemented in the base class.
|
|
11871
12408
|
Please override this method in your extended class.`);
|
|
11872
12409
|
}
|
|
11873
12410
|
getBillboardMediaToEmbed(object) {
|
|
11874
|
-
|
|
11875
|
-
|
|
12411
|
+
// Default implementation to prevent crash if base class is instantiated directly.
|
|
12412
|
+
// Extended classes should override this method.
|
|
12413
|
+
return { comment: null, tagDescription: '' };
|
|
11876
12414
|
}
|
|
11877
12415
|
onActionDetailClick(url) {
|
|
11878
|
-
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
12416
|
+
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
11879
12417
|
Please override this method in your extended class.`);
|
|
11880
12418
|
}
|
|
11881
12419
|
onActionAudioClick(audioCommentID) {
|
|
11882
|
-
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
12420
|
+
throw new Error(`onActionDetailClick is not implemented in the base class.
|
|
11883
12421
|
Please override this method in your extended class.`);
|
|
11884
12422
|
}
|
|
11885
12423
|
onActionVideoClick(url) {
|
|
11886
|
-
throw new Error(`onActionVideoClick is not implemented in the base class.
|
|
12424
|
+
throw new Error(`onActionVideoClick is not implemented in the base class.
|
|
11887
12425
|
Please override this method in your extended class.`);
|
|
11888
12426
|
}
|
|
11889
12427
|
onActionImageClick(imageCommentID) {
|
|
@@ -11891,11 +12429,11 @@ class BaseTagService {
|
|
|
11891
12429
|
Please override this method in your extended class.`);
|
|
11892
12430
|
}
|
|
11893
12431
|
onActionDocClick(url) {
|
|
11894
|
-
throw new Error(`onActionDocClick is not implemented in the base class.
|
|
12432
|
+
throw new Error(`onActionDocClick is not implemented in the base class.
|
|
11895
12433
|
Please override this method in your extended class.`);
|
|
11896
12434
|
}
|
|
11897
12435
|
onActionYoutubeClick(url) {
|
|
11898
|
-
throw new Error(`onActionYoutubeClick is not implemented in the base class.
|
|
12436
|
+
throw new Error(`onActionYoutubeClick is not implemented in the base class.
|
|
11899
12437
|
Please override this method in your extended class.`);
|
|
11900
12438
|
}
|
|
11901
12439
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: BaseTagService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
@@ -12022,7 +12560,7 @@ class MatterportImportService {
|
|
|
12022
12560
|
return new Promise((res, rej) => {
|
|
12023
12561
|
iframe.addEventListener('load', async () => {
|
|
12024
12562
|
try {
|
|
12025
|
-
this.sdk = await showcaseWindow.MP_SDK.connect(iframe, 'qn9wsasuy5h2fzrbrn1nzr0id', '
|
|
12563
|
+
this.sdk = await showcaseWindow.MP_SDK.connect(iframe, 'qn9wsasuy5h2fzrbrn1nzr0id', '');
|
|
12026
12564
|
// Subscribe to Floor data
|
|
12027
12565
|
this.sdk.Floor.data.subscribe({
|
|
12028
12566
|
onCollectionUpdated: function upd(collection) {
|
|
@@ -12152,7 +12690,7 @@ class MatterportImportService {
|
|
|
12152
12690
|
const start = overrideExisting ? 0 : await this.getUploadedImageCount(this.modelID);
|
|
12153
12691
|
for (let index = start; index < nmbScans; index += 1) {
|
|
12154
12692
|
if (!this.stop) {
|
|
12155
|
-
await this.sdk.Sweep.moveTo(scans[index].uuid, { rotation: { x: 0, y: 0 }, transition: this.sdk.
|
|
12693
|
+
await this.sdk.Sweep.moveTo(scans[index].uuid, { rotation: { x: 0, y: 0 }, transition: this.sdk.Camera.TransitionType.INSTANT, transitionTime: 0 });
|
|
12156
12694
|
const img = await this.sdk.Renderer.takeEquirectangular({ width: 2048, height: 1024 }, { mattertags: false, sweeps: true });
|
|
12157
12695
|
/**Upload on S3 are asynchronous, in order to no slow down the process*/
|
|
12158
12696
|
uploadBase64ImageWithRetry(img, scans[index].uuid, `visits/${this.modelID}/sweeps/`, 'sweep', 5).then((r) => {
|
|
@@ -12875,5 +13413,5 @@ function floatValidator() {
|
|
|
12875
13413
|
* Generated bundle index. Do not edit.
|
|
12876
13414
|
*/
|
|
12877
13415
|
|
|
12878
|
-
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, MatterportImportService, MatterportService, 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, arraysContainSameElements, checkElementById, convertTimestampToLocalZone, dateHasExpired, dateTimeToLocalString, deleteFromS3, downloadBlob, downloadEquipmentDocument, downloadFile, downloadFileAsObject, durationToString, emailValidator, enumToArray, filterUniqueArrayByID, floatValidator, getBufferForFileFromS3, getCoefficientsForImage, getDistanceBetweenTwoPoints, getHighestLevelForMissions, getHighestRoleForMissions, getLevelsBelow, getLocaleLong, getLocaleShort, getMetaForImage, getRolesBelowForManager, getSignedFile, getSignedImageUrlForEquipment, getSignedImageUrlForProfile, getSignedImageUrlForSpace, getSpaceIDFromUrl, getVisitUrl, isEmptyObject, listFilesInFolder, mean, noEmptyValidator, numberToDateString, openDocument, openModalForVisitSwitch, poiTypeToString, removeAllFilesFromFolderS3, removeNullKeysFromObject, showScanPointsOnPlanInDiv, shuffleArray, sortAlphabeticallyOnName, stringLocaleToEnum, stringToLowercaseNoSpaces, styleButton, textValidator, translateDatePeriod, uploadBase64Image, uploadBase64ImageWithRetry, uploadFileToS3, uploadJsonToS3, validEmail, wait, waitUntil };
|
|
13416
|
+
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, MatterportImportService, MatterportService, 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, arraysContainSameElements, checkElementById, convertTimestampToLocalZone, dateHasExpired, dateTimeToLocalString, deleteFromS3, 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 };
|
|
12879
13417
|
//# sourceMappingURL=smarterplan-ngx-smarterplan-core.mjs.map
|