architwin 1.14.9 → 1.14.11

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.
@@ -219,7 +219,7 @@ i18n
219
219
  "ViewingInstructions": "During a remote space sharing session, you cannot navigate around the space, only your host has control during the session",
220
220
  "Pending": "Pending",
221
221
  "NowSharing": "Now Sharing",
222
- "ConfirmLeaveSession": "画面共有を終了しますか?",
222
+ "ConfirmLeaveSession": "Do you want to leave sharing session?",
223
223
  "ConfirmLeaveSessionReminder": "",
224
224
  "InSession": "In Session",
225
225
  "Leave": "Leave",
@@ -54,7 +54,7 @@ export function renderRoomFormPane() {
54
54
  </div>
55
55
  <form class="at_form_container at_scrollable_container at_h-min-70" id="at-room-form" data-cy="at-room-form">
56
56
  <div class="at-field at_flex_row">
57
- <label for="">${i18n.t('Name')}</label>
57
+ <label for="" style="font-size: 0.95rem;">${i18n.t('Name')}</label>
58
58
  <input class="at_field_input at_w-full" type="text" name="room_name" id="at-room-name-input" data-cy="at-room-name-input" placeholder="Room 1">
59
59
  </div>
60
60
  <div class="at-field at_flex_column">
@@ -105,13 +105,13 @@ export function renderRoomFormPane() {
105
105
  <span class="mdi mdi-chevron-left at_back_btn" id="at-back-floors"></span>
106
106
  <label for="">
107
107
  <span class="mdi mdi-vector-polygon"></span>
108
- ${i18n.t('WindowsDoors')}
108
+ <span id="at-wall-name"></span>
109
109
  </label>
110
110
  <div> </div>
111
111
  </div>
112
112
 
113
113
  <div class="at_edit_name" id="at-edit-wall-material" style="display: none;">
114
- <input class="at_edit_name_input" type="text" id="at-edit-wall-input" data-cy="at-edit-wall-material-input" placeholder="${i18n.t('EnterWallMaterial')}" disabled>
114
+ <input class="at_edit_name_input" type="text" id="at-edit-wall-input" data-cy="at-edit-wall-material-input" placeholder="${i18n.t('EnterWallMaterial')}" disabled style="font-size: 0.75rem !important;">
115
115
  <span class="mdi mdi-pencil" style="display: none; cursor: pointer;" id="at-wall-edit-material-btn"></span>
116
116
  <span class="mdi mdi-check" id="at-confirm-edit-wall-btn" style="display: none;"></span>
117
117
  </div>
@@ -247,6 +247,7 @@ export function toggleDrawWindowButton() {
247
247
  targetUUID: currentWall.uuid
248
248
  }
249
249
  };
250
+ log.info("drawingConfig", drawingConfig);
250
251
  setDrawingConfig(drawingConfig);
251
252
  startDraw();
252
253
  }
@@ -733,43 +734,17 @@ function displayFaces(polygon) {
733
734
  floorMaterialEdit.style.display = "none";
734
735
  floorMaterialConfirm.style.display = "block";
735
736
  }));
736
- addEventListenerById('at-confirm-edit-wall-btn', (event) => __awaiter(this, void 0, void 0, function* () {
737
+ addEventListenerById('at-confirm-edit-wall-btn', () => __awaiter(this, void 0, void 0, function* () {
737
738
  console.log('@caroline wall check', wallMaterial, currentWall.material, currentWall);
738
739
  const wallEditMaterial = document.getElementById('at-wall-edit-material-btn');
739
740
  const wallConfirmMaterial = document.getElementById('at-confirm-edit-wall-btn');
740
741
  const wallMaterialInput = document.getElementById('at-edit-wall-input');
741
- const partitionData = JSON.parse(currentPartitionData.polygon_json);
742
- const currentPartition = _3DXObjects.find(obj => obj.object.object_data.uuid === currentPartitionData.uuid);
743
- if (partitionData) {
744
- const wallIndex = partitionData.walls.findIndex(wall => wall.uuid == currentWall.uuid);
745
- if (wallIndex != undefined) {
746
- partitionData.walls[wallIndex].material = wallMaterial;
747
- }
748
- currentPartitionData.polygon_json = JSON.stringify(partitionData);
749
- console.log('@caroline partition data: ', currentPartitionData);
750
- }
751
- currentPartitionDataArray.some(partition => {
752
- const parsed = JSON.parse(partition.polygon_json);
753
- parsed.walls.find(wall => {
754
- if (wall.uuid == currentWall.uuid) {
755
- wall.material = wallMaterial;
756
- }
757
- });
758
- });
759
- console.log('[wall] currentPartition: ', currentPartition);
760
- if (currentPartition) {
761
- const wall = currentPartition.object.object_data.json_data.walls.find(wall => wall.uuid == currentWall.uuid);
762
- wall.material = wallMaterial;
763
- }
764
- currentWall.material = wallMaterial;
765
- //rerender to display material value in space
766
- const polyData = {
767
- uuid: currentPartition.object.object_data.uuid,
768
- polygon_json: partitionData
769
- };
770
- // renderPolygon(polyData)
771
- console.log('[wall] Partition to be saved: ', currentPartitionData, JSON.parse(currentPartitionData.polygon_json));
772
- dispatchSpaceEvent(SPACE_EVENTS.PARTITION_EDITED, { data: currentPartitionData });
742
+ const newMaterial = wallMaterialInput.value.trim();
743
+ log.info("newMaterial", newMaterial);
744
+ currentWall.material = newMaterial;
745
+ log.info("currentWall", currentWall);
746
+ log.info("currentObject", currentObject);
747
+ saveWallChanges();
773
748
  wallMaterialInput.disabled = true;
774
749
  wallEditMaterial.style.display = "block";
775
750
  wallConfirmMaterial.style.display = "none";
@@ -804,8 +779,8 @@ function displayWall(wall) {
804
779
  <div class="at_subitem_left">
805
780
  <span class="mdi mdi-vector-line"></span>
806
781
  </div>
807
- <div class="at_subitem_center" id="at-expand-btn-${wall.uuid}" data-cy="at-expand-btn-${wall.uuid}">
808
- ${wallName}
782
+ <div class="at_subitem_center" id="at-expand-btn-${wall.uuid}" data-cy="at-expand-btn-${wall.uuid}" style="width: 150px !important;">
783
+ ${i18n.t('WindowsDoors')}
809
784
  <span class="mdi mdi-chevron-up" id="at-chevron-${wall.uuid}"></span>
810
785
  </div>
811
786
  <div class="at_subitem_right at_invisible">
@@ -932,10 +907,10 @@ function setupEditWindow(element, window) {
932
907
  confirmBtn.style.display = "none";
933
908
  const windowTooltip = document.getElementById(`at-window-name-tooltip-${window.index}`);
934
909
  windowTooltip.innerText = `${window.name}`;
935
- saveWindowChanges();
910
+ saveWallChanges();
936
911
  });
937
912
  }
938
- function saveWindowChanges() {
913
+ function saveWallChanges() {
939
914
  updateWallInPolygon(currentWall);
940
915
  updatePartitionData();
941
916
  setCurrentPolygon(currentObject);
@@ -995,7 +970,7 @@ function setupDeleteWindow(element, window) {
995
970
  });
996
971
  // Save + rerender window
997
972
  currentObject.object.object_data.json_data = currentPolygonData;
998
- saveWindowChanges();
973
+ saveWallChanges();
999
974
  notify.success(`${i18n.t('SuccessWindowDelete')}`);
1000
975
  log.info("currentPartition polygonJson", JSON.parse(currentPartitionData.polygon_json));
1001
976
  log.info("currentObject", currentObject);
@@ -1076,7 +1051,7 @@ function displayFloor(floor, walls, floorModel) {
1076
1051
  </div>
1077
1052
 
1078
1053
  <div class="at_edit_name" id="at-edit-floor-material">
1079
- <input class="at_edit_name_input at_ml_1" type="text" id="at-edit-floor-material-input" data-cy="at-edit-floor-material-input" value="${floor.material ? floor.material : ''}" placeholder="${i18n.t('EnterFloorMaterial')}">
1054
+ <input class="at_edit_name_input at_ml_1" type="text" id="at-edit-floor-material-input" data-cy="at-edit-floor-material-input" value="${floor.material ? floor.material : ''}" placeholder="${i18n.t('EnterFloorMaterial')}" style="font-size: 0.75rem !important;">
1080
1055
  <span class="mdi mdi-pencil at_mr-1" style="display: none; cursor: pointer;" id="at-floor-edit-material-btn"></span>
1081
1056
  <span class="mdi mdi-check at_mr-1" id="at-confirm-edit-floor-name" style="display: none;"></span>
1082
1057
  </div>
@@ -1431,6 +1406,7 @@ export function setCurrentPartitionData() {
1431
1406
  }
1432
1407
  if (drawingMode === 'partition') {
1433
1408
  displayFaceLists();
1409
+ currentObject = currentObjectData;
1434
1410
  }
1435
1411
  }, 50); // Check every 50ms
1436
1412
  });
@@ -1495,7 +1471,7 @@ function updatePartitionDataArray(payload, currentPartitionDataArray) {
1495
1471
  if (existingIndex === -1) {
1496
1472
  if (payload.name == null)
1497
1473
  payload.name = partitionName.value || `${i18n.t('Partition')} ${currentPartitionDataArray.length + 1}`;
1498
- log.info("@@ payload", payload.name);
1474
+ log.info("payload", payload.name);
1499
1475
  // Add the new partition
1500
1476
  currentPartitionDataArray.push(payload);
1501
1477
  newlyAddedPartition.push(payload);
@@ -1640,7 +1616,6 @@ export function handlePartitionWallEditBtn(wallUuid) {
1640
1616
  log.info("currentPartitionData", currentPartitionData);
1641
1617
  log.info("polygonJson", JSON.parse(currentPartitionData.polygon_json));
1642
1618
  log.info("getCurrentPolygon()", getCurrentPolygon());
1643
- setDrawingMode(false);
1644
1619
  const elements = {
1645
1620
  'at-face-title': 'none',
1646
1621
  'at-window-door-title': 'flex',
@@ -1654,6 +1629,7 @@ export function handlePartitionWallEditBtn(wallUuid) {
1654
1629
  });
1655
1630
  const faceVertexContainer = document.getElementById('at-face-vertex-container');
1656
1631
  faceVertexContainer.innerHTML = '';
1632
+ const wallName = document.getElementById('at-wall-name');
1657
1633
  currentWall = JSON.parse(currentPartitionData.polygon_json).walls.find((wall) => wall.uuid == wallUuid);
1658
1634
  log.info("currenWall", currentWall);
1659
1635
  const wallBottomMidPoint = {
@@ -1665,10 +1641,18 @@ export function handlePartitionWallEditBtn(wallUuid) {
1665
1641
  z: ((currentWall.edges[0].start.z + currentWall.edges[1].start.z + currentWall.edges[2].start.z + currentWall.edges[3].start.z) / 4),
1666
1642
  };
1667
1643
  yield goToPosition(wallBottomMidPoint);
1644
+ const match = currentWall.name.match(/wall-(\d+)$/);
1645
+ if (match) {
1646
+ console.log('@caroline wall test display: ', match);
1647
+ const wallNumber = parseInt(match[1]) + 1;
1648
+ wallName.innerText = `${i18n.t('Wall')} ${wallNumber}`;
1649
+ }
1668
1650
  faceVertexContainer.append(displayWall(currentWall));
1669
1651
  //sets material and icon
1670
1652
  setWallMaterial(currentWall.material);
1671
1653
  setWallMaterialIcon(currentWall.material);
1654
+ currentPolygonData = JSON.parse(currentPartitionData.polygon_json);
1655
+ setDrawingMode(false);
1672
1656
  cancelDrawing();
1673
1657
  });
1674
1658
  }
@@ -404,7 +404,7 @@ function toggleSelectedPartition() {
404
404
  handlePartitionRowEditBtnClickEvent(currentEditRoomData.children, partitionRowEdit);
405
405
  if (isWall) {
406
406
  const polygonId = target.getAttribute('polygon-item-id');
407
- handlePartitionWallEditBtn(polygonId);
407
+ yield handlePartitionWallEditBtn(polygonId);
408
408
  }
409
409
  }
410
410
  else {
@@ -4,6 +4,7 @@ export declare let selectedIoTSystem: string;
4
4
  export declare let selectedIotTag: any;
5
5
  export declare function renderTagIOTFormPane(): HTMLDivElement;
6
6
  export declare function setIotCategoryOptions(): void;
7
+ export declare function getIotCategoryOption(): ITagIOTCategory;
7
8
  export declare function toggleIoTCategoryOptions(): void;
8
9
  export declare function toggleIoTDevicesOptions(): void;
9
10
  /**
@@ -11,17 +11,20 @@ import { IOT_LINKED_SYSTEMS, SPACE_EVENTS, TAG_TYPE } from '../../../types';
11
11
  import log from 'loglevel';
12
12
  import i18n from './i18n';
13
13
  import { dispatchSpaceEvent, _tagIotCategoryTypes, _tagIotDevices, _tags } from '../../../architwin';
14
- import { stringContains } from "../../../utils";
14
+ import { stringContains, generateUUID } from "../../../utils";
15
15
  import { batchAddEventListenerByClassName } from '../../events';
16
+ import { toggleModal, setModalAction } from "./modal";
17
+ import { Notyf } from 'notyf';
16
18
  let selectedIoTCatOption;
17
19
  let selectedIoTDeviceOption;
18
20
  export let iotTagFormMode = "ADD" /* FORM_MODE.ADD */;
19
21
  export let selectedIoTSystem = '';
20
22
  export let selectedIotTag = undefined;
21
23
  let tagIotName, iotModelName, iotSerialNumber, iotMfrName, iotSystemLink;
22
- let selectedIoTCatId;
24
+ let selectedIoTCat;
23
25
  let linkedDevicesArray = [];
24
26
  let iotCategoryIconList = ['mdi-power', 'mdi-thermometer', 'mdi-water-percent', 'mdi-gauge', 'mdi-leak', 'mdi-water', 'mdi-lightbulb-on', 'mdi-gas-cylinder', 'mdi-flask', 'mdi-meter-electric', 'mdi-information-symbol', 'mdi-sine-wave'];
27
+ let notify = new Notyf({ position: { x: 'left', y: 'bottom' } });
25
28
  export function renderTagIOTFormPane() {
26
29
  const element = document.createElement('div');
27
30
  element.classList.add('at_container');
@@ -34,7 +37,7 @@ export function renderTagIOTFormPane() {
34
37
  </div>
35
38
 
36
39
  <div class="at_form_container at_scrollable_container at_h-min-70">
37
- <label for="">${i18n.t('Linked Systems')}</label>
40
+ <label for="">${i18n.t('LinkedSystems')}</label>
38
41
  <div class="at_gap_2" style="display: inline-flex">
39
42
  <label class="at_flex at_align_center at_text_xs at_gap_1">
40
43
  <input type="radio" id="at-linked-radio-bemac" name="iot-link-system" checked value=${IOT_LINKED_SYSTEMS.BEMAC} selected />
@@ -46,7 +49,7 @@ export function renderTagIOTFormPane() {
46
49
  </label>
47
50
  <label class="at_flex at_align_center at_text_xs at_gap_1">
48
51
  <input type="radio" id="at-linked-radio-link" name="iot-link-system" value=${IOT_LINKED_SYSTEMS.URL_LINK} />
49
- ${i18n.t("URL Link")}
52
+ ${i18n.t("URLLink")}
50
53
  </label>
51
54
  </div>
52
55
 
@@ -73,22 +76,22 @@ export function renderTagIOTFormPane() {
73
76
  </div>
74
77
 
75
78
  <div class="at-field at_flex_row at_justify_between">
76
- <label for="">${i18n.t('Model Name')}</label>
79
+ <label for="">${i18n.t('ModelName')}</label>
77
80
  <input class="at_field_input at_w-full" type="text" name="model_name" id="at-iot-model-input" data-cy="at-iot-model-input" />
78
81
  </div>
79
82
 
80
83
  <div class="at-field at_flex_row at_justify_between">
81
- <label for="">${i18n.t('Serial Number')}</label>
84
+ <label for="">${i18n.t('SerialNumber')}</label>
82
85
  <input class="at_field_input at_w-full" type="text" name="serial_name" id="at-iot-serial-input" data-cy="at-iot-serial-input" />
83
86
  </div>
84
87
 
85
88
  <div class="at-field at_flex_row at_justify_between">
86
- <label for="">${i18n.t('Manufacturer Site')}</label>
89
+ <label for="">${i18n.t('ManufacturerSite')}</label>
87
90
  <input class="at_field_input at_w-full" type="text" name="manufacturer_site" id="at-iot-manufacturer-input" data-cy="at-iot-manufacturer-input" />
88
91
  </div>
89
92
 
90
93
  <div class="at-field at_flex_row at_justify_between" id="at-iot-system-link-container" style="display: none">
91
- <label for="">${i18n.t('System Link')}</label>
94
+ <label for="">${i18n.t('SystemLink')}</label>
92
95
  <input class="at_field_input at_w-full" type="text" name="system_link" id="at-iot-system-link-input" data-cy="at-iot-system-link-input" />
93
96
  </div>
94
97
 
@@ -98,9 +101,9 @@ export function renderTagIOTFormPane() {
98
101
  </div>
99
102
 
100
103
  <div class="at_field at_flex_column" id="at-iot-device-main-container">
101
- <label for="">${i18n.t('IOT Devices')}</label>
102
- <div id="at-iot-devices-dropdown" data-cy="at-iot-devices-dropdown">
103
- <div id="at-setting-map-filter-dropdown" class="at_dropdown at_flex at_flex_row at_space_between">
104
+ <label for="">${i18n.t('IoTDevices')}</label>
105
+ <div id="at-iot-devices-dropdown" data-cy="at-iot-devices-dropdown" class="at-device-dropdown">
106
+ <div id="at-iot-devices-filter-dropdown" class="at_dropdown at_flex at_flex_row at_space_between">
104
107
  <div class="at_dropdown_toggle" id="at-iot-selected-device" data-cy="at-iot-selected-device">${i18n.t(selectedIoTDeviceOption)}</div>
105
108
  <span class="mdi mdi-chevron-down at_chevron" id="at-iot-cat-filter-chevron" data-cy="at-iot-cat-filter-chevron"></span>
106
109
  </div>
@@ -112,17 +115,19 @@ export function renderTagIOTFormPane() {
112
115
  </div>
113
116
  </div>
114
117
 
115
- <div class="at_partition_list_container at_h-min-40" id="at-iot-device-list-container" data-cy="at-iot-device-list-container">
118
+ <div class="at_iot_list_container at_h-min-40" id="at-iot-device-list-container" data-cy="at-iot-device-list-container">
116
119
 
117
- <div class="at_partition_item_container at_scrollable_container" id="at-linked-device-container" data-cy="at-linked-device-container">
120
+ <div class="at_section at_iot_item_container at_scrollable_container" id="at-linked-device-container" data-cy="at-linked-device-container">
118
121
 
119
- <div class="at_partition_title" style="padding-left: 20px !important;">
122
+ <div class="at_title" style="padding-left: 20px !important;">
120
123
  <div> </div>
121
- <label for="">${i18n.t('Linked IOT Devices')}</label>
124
+ <label for="">${i18n.t('LinkedIoTDevices')}</label>
122
125
  <div> </div>
123
126
  </div>
124
127
 
125
- <div class="at_linked_device_container" id="at-linked-device-row">
128
+ <div>
129
+ <div class="at_body at_linked_device_container" id="at-device-item-container">
130
+ </div>
126
131
  </div>
127
132
 
128
133
  </div>
@@ -155,19 +160,24 @@ function displayFormTitle() {
155
160
  title.innerHTML = '';
156
161
  const span = document.createElement('span');
157
162
  span.textContent = iotTagFormMode === "ADD" /* FORM_MODE.ADD */
158
- ? i18n.t('Add IOT Tag')
159
- : i18n.t('Edit IOT Tag');
163
+ ? i18n.t('AddIoTTag')
164
+ : i18n.t('EditIoTTag');
160
165
  title.appendChild(span);
161
166
  }
167
+ // displays selected Category in the dropdown
162
168
  function setSelectedIoTCat(payload) {
163
169
  log.info('setSelectedIoTCat()', payload);
164
170
  const selectedOption = document.getElementById('at-iot-selected-cat');
165
- selectedOption.innerText = payload;
171
+ selectedOption.innerText = i18n.t(payload.name);
166
172
  }
173
+ // displays selected Device in the dropdown
167
174
  function setSelectedIoTDevice(payload) {
168
175
  log.info('setSelectedIoTDevice()', payload);
169
176
  const selectedDevice = document.getElementById('at-iot-selected-device');
170
- selectedDevice.innerText = payload;
177
+ selectedDevice.innerText = '';
178
+ if (payload) {
179
+ selectedDevice.innerText = payload;
180
+ }
171
181
  }
172
182
  function setInputFields() {
173
183
  log.info('setInputFields()');
@@ -180,17 +190,37 @@ function setInputFields() {
180
190
  export function setIotCategoryOptions() {
181
191
  log.info('setIotCategoryOptions()');
182
192
  dispatchSpaceEvent(SPACE_EVENTS.GET_IOT_CATEGORIES, { payload: 'hello from library' });
183
- renderIotCategoryDropdownOptions('at-iot-category-options', _tagIotCategoryTypes);
184
- batchAddEventListenerByClassName('at_iot_cat_option', (event) => {
185
- //@ts-ignore
186
- const selectedCat = event.target;
187
- const dataCy = selectedCat.getAttribute('data-cy');
188
- const match = dataCy.match(/^at-iot-category-option-(.+)$/);
189
- const selectedId = match ? match[1] : null;
190
- selectedIoTCatId = selectedCat.innerText; // this is set to inner text as uuid for category changes due to dummy data
191
- setSelectedIoTCat(selectedCat.innerText);
192
- log.info('cat id: ', selectedIoTCatId);
193
- });
193
+ if (_tagIotCategoryTypes) {
194
+ renderIotCategoryDropdownOptions('at-iot-category-options', _tagIotCategoryTypes);
195
+ batchAddEventListenerByClassName('at_iot_cat_option', (event) => {
196
+ //@ts-ignore
197
+ const selectedCat = event.target;
198
+ const catUUID = selectedCat.getAttribute('iot-category-uuid');
199
+ const getCatName = _tagIotCategoryTypes.find(cat => cat.uuid === catUUID);
200
+ if (getCatName) {
201
+ selectedIoTCat = { uuid: catUUID, name: getCatName.name };
202
+ setSelectedIoTCat(selectedIoTCat);
203
+ log.info('cat id: ', selectedIoTCat);
204
+ }
205
+ });
206
+ }
207
+ }
208
+ // gets selected Category and returns the object
209
+ export function getIotCategoryOption() {
210
+ log.info('getIotCategoryOption()');
211
+ let foundCat = {};
212
+ if (linkedDevicesArray.length > 1) {
213
+ foundCat = _tagIotCategoryTypes.find((cat) => {
214
+ return i18n.t(cat.name) === 'Multiple';
215
+ });
216
+ }
217
+ else {
218
+ foundCat = _tagIotCategoryTypes.find((cat) => {
219
+ return i18n.t(cat.uuid) === selectedIoTCat.uuid;
220
+ });
221
+ }
222
+ log.info('foundCat: ', foundCat);
223
+ return foundCat;
194
224
  }
195
225
  export function toggleIoTCategoryOptions() {
196
226
  log.info('toggleIoTCategoryOptions');
@@ -250,7 +280,7 @@ export function clearIoTDropdowns() {
250
280
  const catDropdown = document.getElementById('at-iot-selected-cat');
251
281
  const devicesDropdown = document.getElementById('at-iot-selected-device');
252
282
  catDropdown.innerText = i18n.t('NoSelection');
253
- devicesDropdown.innerText = i18n.t('Select Device');
283
+ devicesDropdown.innerText = i18n.t('SelectDevice');
254
284
  }
255
285
  /**
256
286
  * Initializes Form Data
@@ -260,12 +290,14 @@ export function clearIoTDropdowns() {
260
290
  export function initIoTFormData(tagId) {
261
291
  log.info('initIoTFormData()');
262
292
  displayFormTitle();
293
+ const iotSave = document.getElementById('at-save-iot-btn');
294
+ iotSave.classList.remove('at_disabled');
263
295
  // Add Mode
264
296
  if (!tagId) {
265
- log.info('initIoTFormData() tagId not Exist: ', iotTagFormMode);
297
+ clearIoTDropdowns();
298
+ clearIotFields();
266
299
  if (iotTagFormMode == "ADD" /* FORM_MODE.ADD */) {
267
300
  if (tagIotName === null || tagIotName == undefined) {
268
- log.info('initIoTFormData() tagname check', tagIotName);
269
301
  setInputFields();
270
302
  }
271
303
  tagIotName.value = '';
@@ -273,11 +305,12 @@ export function initIoTFormData(tagId) {
273
305
  iotSerialNumber.value = '';
274
306
  iotMfrName.value = '';
275
307
  iotSystemLink.value = '';
308
+ linkedDevicesArray = [];
309
+ setIotDeviceOptions();
276
310
  }
277
311
  }
278
312
  else {
279
313
  const foundTag = _tags.find(tag => tag.json_data.id === tagId);
280
- log.info('initIoTFormData() foundTag: ', foundTag, _tags);
281
314
  if (foundTag) {
282
315
  selectedIotTag = foundTag;
283
316
  if (tagIotName === null || tagIotName == undefined) {
@@ -299,23 +332,25 @@ export function initIoTFormData(tagId) {
299
332
  setSelectedIoTSystemRadio(IOT_LINKED_SYSTEMS.BEMAC);
300
333
  }
301
334
  if (iotData.iot_category) {
302
- const cat = _tagIotCategoryTypes.find(cat => cat.name === iotData.iot_category);
335
+ log.info('found cat 1: ', i18n.t(iotData.iot_category), iotData.iot_category, _tagIotCategoryTypes);
336
+ const cat = _tagIotCategoryTypes.find(cat => i18n.t(cat.name.toLocaleLowerCase()) === iotData.iot_category.toLocaleLowerCase());
303
337
  if (cat) {
304
- setSelectedIoTCat(cat.name);
305
- selectedIoTCatId = cat.name;
338
+ log.info('found cat: ', cat);
339
+ setSelectedIoTCat({ uuid: cat.uuid, name: cat.name });
340
+ selectedIoTCat = { uuid: cat.uuid, name: cat.name };
306
341
  }
307
342
  else {
308
343
  // for the Dummy data from App Side
309
- setSelectedIoTCat(i18n.t('NoSelection'));
344
+ setSelectedIoTCat({ uuid: generateUUID(), name: i18n.t('NoSelection') });
310
345
  renderIotCategoryDropdownOptions('at-iot-category-options', _tagIotCategoryTypes);
311
346
  }
312
347
  }
313
348
  log.info("iotData.linked_devices: ", iotData.linked_devices);
314
349
  if (iotData.linked_devices && iotData.linked_devices.length > 0) {
350
+ setIotDeviceOptions();
315
351
  // renderIotDeviceDropdownOptions('at-iot-device-options', _tagIotDevices)
316
352
  setSelectedIoTDevice(iotData.linked_devices[0].name);
317
353
  linkedDevicesArray = iotData.linked_devices;
318
- log.info("EDIT linkedDevicesArray: ", linkedDevicesArray);
319
354
  renderLinkedDevices(linkedDevicesArray);
320
355
  }
321
356
  else {
@@ -328,7 +363,7 @@ export function initIoTFormData(tagId) {
328
363
  // this is due to selecting the tags created from James
329
364
  log.info('initIoTFormData()', iotData);
330
365
  setSelectedIoTSystemRadio(IOT_LINKED_SYSTEMS.BEMAC);
331
- setSelectedIoTCat('No Selection');
366
+ setSelectedIoTCat({ uuid: generateUUID(), name: i18n.t('NoSelection') });
332
367
  renderIotCategoryDropdownOptions('at-iot-category-options', _tagIotCategoryTypes);
333
368
  renderIotDeviceDropdownOptions('at-iot-device-options', _tagIotDevices);
334
369
  }
@@ -370,8 +405,10 @@ export function renderIotCategoryDropdownOptions(elementId, items) {
370
405
  return;
371
406
  }
372
407
  items.forEach((item, index) => {
373
- const option = createCatOptionElement(item, 'iotcategory', index);
374
- element.appendChild(option);
408
+ if (item.name != 'Multiple') {
409
+ const option = createCatOptionElement(item, 'iotcategory', index);
410
+ element.appendChild(option);
411
+ }
375
412
  });
376
413
  }
377
414
  function createCatOptionElement(item, dropdownType, index) {
@@ -394,28 +431,33 @@ function createCatOptionElement(item, dropdownType, index) {
394
431
  return option;
395
432
  }
396
433
  function selectCatOption(option, elementId) {
397
- log.info('selectCatOption()', option, elementId);
434
+ dispatchSpaceEvent(SPACE_EVENTS.GET_IOT_CAT_ICON, { payload: option });
398
435
  }
436
+ // selects Devices from Arrayat-device-item-container
399
437
  export function setIotDeviceOptions() {
400
438
  log.info('setIotDeviceOptions()');
401
439
  dispatchSpaceEvent(SPACE_EVENTS.GET_IOT_DEVICES, { payload: 'hello from library' });
402
440
  renderIotDeviceDropdownOptions('at-iot-device-options', _tagIotDevices);
403
- batchAddEventListenerByClassName('at_iot_dev_option', (event) => {
441
+ batchAddEventListenerByClassName('at_option', (event) => {
404
442
  //@ts-ignore
405
- const selectedDev = event.target;
406
- const parent = selectedDev.parentElement;
407
- log.info('@caroline parent: ', parent);
443
+ const selectedDev = document.getElementById(event.target.id);
444
+ const parent = selectedDev.closest('div');
408
445
  const deviceId = parent.getAttribute('iot-device-uuid');
409
- log.info('@caroline deviceId: ', deviceId);
410
- const device = _tagIotDevices.find(device => device.id == deviceId);
411
- log.info("device", device);
412
- setSelectedIoTDevice(selectedDev.innerText);
413
- linkedDevicesArray.push(device);
414
- renderLinkedDevices(linkedDevicesArray);
446
+ // adds selected device to array
447
+ const devFound = _tagIotDevices.find(device => device.id === deviceId);
448
+ if (devFound) {
449
+ selectedDev.setAttribute('disabled', 'true');
450
+ setSelectedIoTDevice(selectedDev.innerText);
451
+ linkedDevicesArray.push(devFound);
452
+ //hides the selected device in dropdown
453
+ parent.style.display = 'none'; //hides
454
+ renderDeviceRow(devFound);
455
+ selectedDev.setAttribute('disabled', 'false');
456
+ }
415
457
  });
416
458
  }
417
459
  export function renderIotDeviceDropdownOptions(elementId, items) {
418
- log.info("renderIotDeviceDropdownOptions: ", items);
460
+ log.info("renderIotDeviceDropdownOptions: ");
419
461
  const element = document.getElementById(elementId);
420
462
  if (!element) {
421
463
  console.error("Parameter element is undefined");
@@ -430,19 +472,19 @@ export function renderIotDeviceDropdownOptions(elementId, items) {
430
472
  element.innerHTML = ``;
431
473
  const selectedIotDeviceOption = document.getElementById(isFilterDropdown ? 'at-iot-device-filter-dropdown-toggle' : 'at-iot-device-dropdown-toggle');
432
474
  if (selectedIotDeviceOption) {
433
- selectedIotDeviceOption.textContent = `${i18n.t('Select Device')}`;
475
+ selectedIotDeviceOption.textContent = `${i18n.t('SelectDevice')}`;
434
476
  selectedIoTDeviceOption = undefined;
435
477
  }
436
478
  //Add the no selection option
437
479
  const selectDevice = document.createElement('div');
438
- selectDevice.classList.add('at_iot_dev_option');
480
+ selectDevice.classList.add('at_option');
439
481
  selectDevice.setAttribute('iot-device-uuid', '');
440
482
  selectDevice.setAttribute('dropdown-type', 'iotdevice');
441
483
  selectDevice.innerHTML = `
442
- <span></span> ${i18n.t('Select Device')}
484
+ <span></span> ${i18n.t('SelectDevice')}
443
485
  `;
444
486
  selectDevice.onclick = () => {
445
- log.info('@caroline onClick');
487
+ log.info('item selected: ', selectDevice, linkedDevicesArray);
446
488
  selectDeviceOption(selectDevice, isFilterDropdown ? 'at-iot-device-filter-dropdown-toggle' : 'at-iot-device-filter-dropdown-toggle');
447
489
  };
448
490
  element.appendChild(selectDevice);
@@ -466,21 +508,23 @@ function createDeviceOptionElement(item, dropdownType) {
466
508
  option.style.justifyContent = 'left';
467
509
  option.style.alignItems = 'center';
468
510
  option.style.gap = '2px';
511
+ // option.classList.add('at_option')
469
512
  option.classList.add('at_option');
470
- option.classList.add('at_iot_dev_option');
471
513
  option.setAttribute('iot-device-uuid', item.id);
472
514
  option.setAttribute('dropdown-type', dropdownType);
473
515
  option.setAttribute('data-cy', `at-iot-category-option-${item.id}`);
474
- if (dropdownType == 'category') {
475
- option.innerHTML = `
476
- <span class="at_colored-indicator"></span>
477
- ${item.name}
478
- `;
479
- return option;
480
- }
481
516
  option.innerHTML = `
482
- <span>${item.name}</span>
517
+ <span style="width: 100%; display: block; padding: 4px 8px; cursor: pointer" id="${item.id}">${item.name}</span>
483
518
  `;
519
+ if (selectedIotTag) {
520
+ const iotTag = selectedIotTag.iot_tag;
521
+ const hideOption = iotTag.linked_devices.find((dev) => {
522
+ return dev.id === item.id;
523
+ });
524
+ if (hideOption != undefined) {
525
+ option.style.setProperty('display', 'none', 'important');
526
+ }
527
+ }
484
528
  return option;
485
529
  }
486
530
  /**
@@ -499,7 +543,8 @@ export function getIotTagFormData() {
499
543
  modelName: iotModelName.value,
500
544
  serialNumber: iotSerialNumber.value,
501
545
  tagMf: iotMfrName.value,
502
- tagCategoryId: selectedIoTCatId,
546
+ // tagCategoryId: selectedIoTCat.uuid,
547
+ tagCategoryId: selectedIoTCat.name,
503
548
  systemLink: iotSystemLink.value,
504
549
  linkedDevices: linkedDevicesArray,
505
550
  iotSystem: selectedIoTSystem,
@@ -508,55 +553,78 @@ export function getIotTagFormData() {
508
553
  return formData;
509
554
  }
510
555
  function renderLinkedDevices(linkedDevices) {
511
- log.info('renderLinkedDevices()', linkedDevices);
556
+ log.info('renderLinkedDevices()');
512
557
  if (linkedDevices) {
513
- const devicesContainer = document.getElementById('at-linked-device-row');
558
+ // const devicesContainer = document.getElementById('at-device-item-container')
514
559
  if (linkedDevices.length > 0) {
515
- devicesContainer.innerHTML = ``;
516
560
  linkedDevices.forEach(device => {
517
- log.info("@caroline device: ", device);
518
561
  renderDeviceRow(device);
519
562
  });
520
563
  }
521
564
  }
522
565
  }
523
566
  function renderDeviceRow(payload) {
524
- log.info('renderDeviceRow()', payload);
525
- const devicesContainer = document.getElementById('at-linked-device-row');
567
+ log.info('renderDeviceRow()');
568
+ const devicesContainer = document.getElementById('at-device-item-container');
526
569
  if (payload) {
527
570
  const deviceRow = document.createElement('div');
528
571
  deviceRow.classList.add('at_flex_row');
529
- deviceRow.classList.add('at_partition_item');
572
+ deviceRow.classList.add('at_item');
530
573
  deviceRow.innerHTML = `
531
- <div class="at_icon_left">
574
+ <div class="at_subitem_left">
532
575
  <span class="mdi mdi-cube-outline"></span>
533
576
  </div>
534
577
 
535
- <div class="at_partition_name">
578
+ <div class="at_name">
536
579
  <div></div>
537
580
  <label for="">${payload.name}</label>
538
581
  <div></div>
539
582
  </div>
540
- <div class="at_icon_right">
541
- <span class="mdi mdi-delete-outline at_delete_device_btn" id="at-delete-device-${payload.uuid}"></span>
583
+ <div class="at_subitem_right">
584
+ <span class="mdi mdi-delete-outline at_delete_device_btn" id="at-delete-device-${payload.id}"></span>
542
585
  </div>
543
586
  `;
544
587
  devicesContainer.appendChild(deviceRow);
545
588
  batchAddEventListenerByClassName('at_delete_device_btn', (event) => __awaiter(this, void 0, void 0, function* () {
546
- log.info('deleteSelectedLinkedDevice is clicked', event);
547
589
  //@ts-ignore
548
- const selectedDevice = document.getElementById(event.target.id);
590
+ const selectedDevice = event.target;
549
591
  if (selectedDevice) {
550
- log.info('deleteSelectedLinkedDevice', selectedDevice);
551
- // will be tested when using live data
552
- // const devId = extractUUID(selectedDevice.id)
553
- const devId = selectedDevice.id.split('at-delete-partition-')[1];
554
- const findDevice = linkedDevicesArray.findIndex(dev => dev.id == devId);
555
- log.info('deleteSelectedLinkedDevice found device', findDevice, devId);
556
- linkedDevicesArray.splice(findDevice, 1);
557
- const parent = selectedDevice.closest('.at_partition_item');
558
- parent.style.display = 'none';
559
- log.info('deleteSelectedLinkedDevice parent', parent);
592
+ toggleModal();
593
+ setModalAction({
594
+ title: `${i18n.t('DeleteDevice')}`,
595
+ description: `${i18n.t('ConfirmDeleteDevice')}`,
596
+ buttonLabel: `${i18n.t('YesDelete')}`
597
+ }, () => __awaiter(this, void 0, void 0, function* () {
598
+ // gets the device id
599
+ const devId = selectedDevice.id.split('at-delete-device-')[1];
600
+ // finds the index of the selected device
601
+ const findDevice = linkedDevicesArray.findIndex(dev => dev.id === devId);
602
+ if (findDevice > -1) {
603
+ selectedDevice.setAttribute('disabled', 'true');
604
+ const parent = selectedDevice.closest('.at_partition_item');
605
+ if (parent) {
606
+ // displays delete Device back in Dropdown List
607
+ const findHideDev = document.querySelector(`div[iot-device-uuid="${devId}"]`);
608
+ const devicesDropdown = document.getElementById('at-iot-selected-device');
609
+ if (findHideDev) {
610
+ findHideDev.style.display = "block";
611
+ parent.style.display = 'none';
612
+ linkedDevicesArray.splice(findDevice, 1);
613
+ }
614
+ if (linkedDevicesArray.length === 0) {
615
+ devicesDropdown.innerText = i18n.t('SelectDevice');
616
+ setIotDeviceOptions();
617
+ }
618
+ }
619
+ toggleModal(false);
620
+ notify.success(`${i18n.t('SuccessDeleteDevice')}`);
621
+ selectedDevice.setAttribute('disabled', 'false');
622
+ }
623
+ else {
624
+ toggleModal(false);
625
+ notify.error("Tag id not found!");
626
+ }
627
+ }));
560
628
  }
561
629
  }));
562
630
  return;
@@ -573,7 +641,7 @@ export function clearIotFields() {
573
641
  iotSerialNumber = document.getElementById('at-iot-serial-input');
574
642
  iotMfrName = document.getElementById('at-iot-manufacturer-input');
575
643
  iotSystemLink = document.getElementById('at-iot-system-link-input');
576
- const deviceContainer = document.getElementById("linked-devices-container");
644
+ const deviceContainer = document.getElementById('at-device-item-container');
577
645
  tagIotName.innerText = '';
578
646
  iotModelName.innerText = '';
579
647
  iotSerialNumber.innerText = '';
@@ -582,10 +650,9 @@ export function clearIotFields() {
582
650
  linkedDevicesArray = [];
583
651
  selectedIoTSystem = '';
584
652
  setSelectedIoTSystemRadio(IOT_LINKED_SYSTEMS.BEMAC);
585
- if (deviceContainer !== null) {
586
- deviceContainer.innerHTML = '';
587
- }
653
+ deviceContainer.innerHTML = '';
588
654
  iotTagFormMode = "ADD" /* FORM_MODE.ADD */;
655
+ selectedIotTag = undefined;
589
656
  }
590
657
  /**
591
658
  * Sets the form mode for the IOT form.
@@ -6,3 +6,4 @@ export declare function renderViewingRemoteSpace(): HTMLElement;
6
6
  */
7
7
  export declare function renderRemoteSpaceViewing(user: ScreenShareUser): void;
8
8
  export declare function handleRemoteViewResponsiveChanges(): void;
9
+ export declare function handleScreenShareRemoteEndSessionEvent(): void;
@@ -100,3 +100,9 @@ export function handleRemoteViewResponsiveChanges() {
100
100
  container.classList.toggle("at_display_flex_end", isMobile);
101
101
  }
102
102
  }
103
+ export function handleScreenShareRemoteEndSessionEvent() {
104
+ const element = document.getElementById("at-viewing-remote-space-pane");
105
+ if (element) {
106
+ element.style.display = 'none';
107
+ }
108
+ }
@@ -30,7 +30,7 @@ import { getBasepointCalibrateBpCoordinateValues, getBasepointCalibrateMpCoordin
30
30
  import { toggleGeneralMapOptions, initGeneralSelectedMap, getSelectedMapOption } from './components/toolbar/generalSettingsMenuPane';
31
31
  import { searchTagList, setSearchTagTerm, searchClearfield, getSearchTagTerm, sortTags, updateSelectedTagSortOption, resetSelectedTagSortOption } from './components/toolbar/tagListPane';
32
32
  import { renderUserRows } from "./components/toolbar/spaceUserListPane";
33
- import { handleRemoteViewResponsiveChanges, renderRemoteSpaceViewing } from "./components/toolbar/viewingRemoteSpace";
33
+ import { handleRemoteViewResponsiveChanges, handleScreenShareRemoteEndSessionEvent, renderRemoteSpaceViewing } from "./components/toolbar/viewingRemoteSpace";
34
34
  import { PipeList } from "./components/toolbar/pipeListPane";
35
35
  import { PipeForm } from "./components/toolbar/pipeFormPane";
36
36
  import { unsendComment, timedoutComment, getTheseTagMessages } from './components/toolbar/tagMessagingPane';
@@ -1439,6 +1439,7 @@ function setupSpaceEventSubscriptions() {
1439
1439
  subscribeSpaceEvent(SPACE_EVENTS.SCREEN_SHARE_HOST_END_SESSION, handleScreenShareEndSessionEvent);
1440
1440
  subscribeSpaceEvent(SPACE_EVENTS.SCREEN_SHARE_ACCEPT_REQUEST, handleScreenShareAcceptRequest);
1441
1441
  subscribeSpaceEvent(SPACE_EVENTS.SCREEN_SHARE_BACK_USER_LIST_PANE, handleScreenShareBackUserListPane);
1442
+ subscribeSpaceEvent(SPACE_EVENTS.SCREEN_SHARE_TERMINATED, handleScreenShareRemoteEndSessionEvent);
1442
1443
  }
1443
1444
  function handlePartitionColiderClickSelected(payload) {
1444
1445
  return __awaiter(this, void 0, void 0, function* () {
@@ -1529,6 +1530,7 @@ function handleVertexPlace(payload) {
1529
1530
  if (isToolbarFeatureEnabled('roomCreation')) {
1530
1531
  log.info("getDrawingMode()", getDrawingMode());
1531
1532
  if (getDrawingMode() === 'window') {
1533
+ log.info("current polygon", getCurrentPolygon());
1532
1534
  }
1533
1535
  if (getDrawingMode() === 'partition') {
1534
1536
  // setCurrentPartitionData()
@@ -137,6 +137,8 @@ export declare class BufferGeometry {
137
137
  windowData: any;
138
138
  targetIndex: any;
139
139
  targetUUID: any;
140
+ deductWindowFromWallArea: boolean;
141
+ windowOutlineColor: number;
140
142
  };
141
143
  outputs: Record<string, unknown> & MpSdk.Scene.PredefinedOutputs;
142
144
  context: MpSdk.Scene.IComponentContext;
@@ -157,6 +159,20 @@ export declare class BufferGeometry {
157
159
  onTick: (delta: any) => void;
158
160
  onDestroy(): void;
159
161
  createLabelCanvas(text: string): HTMLCanvasElement;
162
+ /**
163
+ * Projects 3D window coordinates to 2D for accurate area calculation
164
+ * @param path3D Array of 3D coordinates
165
+ * @returns Object with area and perimeter calculated from projected 2D coordinates
166
+ */
167
+ calculateWindowDimensions(path3D: Array<{
168
+ x: number;
169
+ y: number;
170
+ z: number;
171
+ }>): {
172
+ area: number;
173
+ perimeter: number;
174
+ };
175
+ calculateWallNormal(wallIndex: number, startPoint: any, endPoint: any): THREE.Vector3;
160
176
  renderWindow(WALL_HEIGHT: number): void;
161
177
  renderWalls(WALL_HEIGHT: number, metadata?: PolygonData): (WallPolyData[] | EdgePolyData[])[];
162
178
  renderWindows(windows: WindowPolyData[]): void;
@@ -511,6 +511,8 @@ export class BufferGeometry {
511
511
  windowData: undefined,
512
512
  targetIndex: undefined,
513
513
  targetUUID: undefined,
514
+ deductWindowFromWallArea: true,
515
+ windowOutlineColor: 0x253D5B
514
516
  };
515
517
  this.emits = {
516
518
  changed: true,
@@ -693,6 +695,17 @@ export class BufferGeometry {
693
695
  if (wall.windows && wall.windows.length > 0) {
694
696
  acc = [...acc, ...wall.windows];
695
697
  wallDataArray[index].windows = wall.windows;
698
+ // if (this.inputs.deductWindowFromWallArea) {
699
+ // // Calculate total window area for this wall
700
+ // let totalWindowArea = 0;
701
+ // if (wall.windows && wall.windows.length > 0) {
702
+ // totalWindowArea = wall.windows.reduce((sum, window) => {
703
+ // return sum + (window.area || 0);
704
+ // }, 0);
705
+ // }
706
+ // // Subtract window area from wall area
707
+ // wallDataArray[index].area = Math.max(0, wallDataArray[index].area - totalWindowArea);
708
+ // }
696
709
  }
697
710
  return acc;
698
711
  }, []);
@@ -728,7 +741,8 @@ export class BufferGeometry {
728
741
  if (!polyData.walls[targetWallIndex].windows)
729
742
  polyData.walls[targetWallIndex].windows = [];
730
743
  const currentWindowCount = polyData.walls[targetWallIndex].windows ? polyData.walls[targetWallIndex].windows.length + 1 : 0;
731
- const windowDimension = PolygonCalculator.calculatePolygonProperties(this.inputs.path, true);
744
+ // Calculate window dimensions using proper 3D to 2D projection
745
+ const windowDimension = this.calculateWindowDimensions(this.inputs.path);
732
746
  let windowDataArray = [];
733
747
  for (let i = 0; i < this.inputs.path.length; i++) {
734
748
  const startPoint = this.inputs.path[i];
@@ -771,6 +785,15 @@ export class BufferGeometry {
771
785
  log.error("Error rendering windows ", error);
772
786
  }
773
787
  polyData.walls[targetWallIndex].windows[this.inputs.targetIndex] = (windowData);
788
+ if (this.inputs.deductWindowFromWallArea) {
789
+ let totalWindowArea = 0;
790
+ if (polyData.walls[targetWallIndex].windows && polyData.walls[targetWallIndex].windows.length > 0) {
791
+ totalWindowArea = polyData.walls[targetWallIndex].windows.reduce((sum, window) => {
792
+ return sum + (window.area || 0);
793
+ }, 0);
794
+ }
795
+ polyData.walls[targetWallIndex].area = Math.max(0, polyData.walls[targetWallIndex].area - totalWindowArea);
796
+ }
774
797
  partitionData = polyData;
775
798
  }
776
799
  }
@@ -817,6 +840,83 @@ export class BufferGeometry {
817
840
  return canvas;
818
841
  }
819
842
  ;
843
+ /**
844
+ * Projects 3D window coordinates to 2D for accurate area calculation
845
+ * @param path3D Array of 3D coordinates
846
+ * @returns Object with area and perimeter calculated from projected 2D coordinates
847
+ */
848
+ calculateWindowDimensions(path3D) {
849
+ const THREE = this.context.three;
850
+ if (!path3D || path3D.length < 3) {
851
+ return PolygonCalculator.calculatePolygonProperties(path3D, true);
852
+ }
853
+ const p0 = new THREE.Vector3(path3D[0].x, path3D[0].y, path3D[0].z);
854
+ const p1 = new THREE.Vector3(path3D[1].x, path3D[1].y, path3D[1].z);
855
+ const p2 = new THREE.Vector3(path3D[2].x, path3D[2].y, path3D[2].z);
856
+ const v1 = new THREE.Vector3().subVectors(p1, p0);
857
+ const v2 = new THREE.Vector3().subVectors(p2, p0);
858
+ const normal = new THREE.Vector3().crossVectors(v1, v2);
859
+ const normalLen = normal.length();
860
+ if (normalLen > 0) {
861
+ normal.divideScalar(normalLen);
862
+ const uAxis = v1.clone().normalize();
863
+ const vAxis = new THREE.Vector3().crossVectors(normal, uAxis).normalize();
864
+ const shapePoints2D = [];
865
+ for (let j = 0; j < path3D.length; j++) {
866
+ const pj = new THREE.Vector3(path3D[j].x, path3D[j].y, path3D[j].z);
867
+ const rel = new THREE.Vector3().subVectors(pj, p0);
868
+ const x = rel.dot(uAxis);
869
+ const y = rel.dot(vAxis);
870
+ shapePoints2D.push(new THREE.Vector2(x, y));
871
+ }
872
+ let twiceSignedArea = 0;
873
+ let perimeter = 0;
874
+ console.log('Window projection debug:');
875
+ console.log('Original 3D points:', path3D);
876
+ console.log('Projected 2D points:', shapePoints2D);
877
+ for (let j = 0; j < shapePoints2D.length; j++) {
878
+ const p1 = shapePoints2D[j];
879
+ const p2 = shapePoints2D[(j + 1) % shapePoints2D.length];
880
+ const cross = p1.x * p2.y - p2.x * p1.y;
881
+ twiceSignedArea += cross;
882
+ const distance = Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
883
+ perimeter += distance;
884
+ console.log(`Edge ${j}: p1(${p1.x.toFixed(3)}, ${p1.y.toFixed(3)}) -> p2(${p2.x.toFixed(3)}, ${p2.y.toFixed(3)}), cross=${cross.toFixed(3)}, distance=${distance.toFixed(3)}`);
885
+ }
886
+ const area = Math.abs(twiceSignedArea * 0.5);
887
+ console.log(`Final calculation: twiceSignedArea=${twiceSignedArea.toFixed(3)}, area=${area.toFixed(3)}, perimeter=${perimeter.toFixed(3)}`);
888
+ return { area, perimeter };
889
+ }
890
+ else {
891
+ return PolygonCalculator.calculatePolygonProperties(path3D, true);
892
+ }
893
+ }
894
+ calculateWallNormal(wallIndex, startPoint, endPoint) {
895
+ const THREE = this.context.three;
896
+ const wallDirection = new THREE.Vector3(endPoint.x - startPoint.x, endPoint.y - startPoint.y, endPoint.z - startPoint.z).normalize();
897
+ if (this.inputs.path.length >= 3) {
898
+ const p0 = new THREE.Vector3(this.inputs.path[0].x, this.inputs.path[0].y, this.inputs.path[0].z);
899
+ const p1 = new THREE.Vector3(this.inputs.path[1].x, this.inputs.path[1].y, this.inputs.path[1].z);
900
+ const p2 = new THREE.Vector3(this.inputs.path[2].x, this.inputs.path[2].y, this.inputs.path[2].z);
901
+ const v1 = new THREE.Vector3().subVectors(p1, p0);
902
+ const v2 = new THREE.Vector3().subVectors(p2, p0);
903
+ const polygonNormal = new THREE.Vector3().crossVectors(v1, v2).normalize();
904
+ const wallNormal = new THREE.Vector3().crossVectors(wallDirection, polygonNormal).normalize();
905
+ // If the normal is too small (wall is parallel to polygon normal), use a fallback
906
+ if (wallNormal.lengthSq() < 0.001) {
907
+ // Use the wall direction rotated 90 degrees around the Y axis
908
+ wallNormal.set(-wallDirection.z, 0, wallDirection.x).normalize();
909
+ }
910
+ return wallNormal;
911
+ }
912
+ // Fallback: use the original method if we don't have enough points
913
+ const up = new THREE.Vector3(0, 1, 0);
914
+ const wallNormal = new THREE.Vector3().crossVectors(wallDirection, up).normalize();
915
+ if (wallNormal.lengthSq() < 0.001) {
916
+ wallNormal.set(1, 0, 0);
917
+ }
918
+ return wallNormal;
919
+ }
820
920
  renderWindow(WALL_HEIGHT) {
821
921
  // const THREE = this.context.three
822
922
  // const windowData:WindowPolyData = this.inputs.windowData
@@ -864,7 +964,19 @@ export class BufferGeometry {
864
964
  wallMesh.add(outlineMesh);
865
965
  wallMesh.name = this.inputs.uuid != '' ? `${this.inputs.uuid}_wall-${i}` : `wall-${i}`;
866
966
  const wallLength = new THREE.Vector3(endPoint.x - startPoint.x, endPoint.y - startPoint.y, endPoint.z - startPoint.z).length();
867
- const wallArea = wallLength * WALL_HEIGHT;
967
+ let wallArea = wallLength * WALL_HEIGHT;
968
+ if (this.inputs.deductWindowFromWallArea && metadata) {
969
+ const currentWallIndex = wallDataArray.length == 0 ? wallDataArray.length : wallDataArray.length - 1;
970
+ let totalWindowArea = 0;
971
+ if (metadata.walls[currentWallIndex].windows && metadata.walls[currentWallIndex].windows.length > 0) {
972
+ totalWindowArea = metadata.walls[currentWallIndex].windows.reduce((sum, window) => {
973
+ const dimension = this.calculateWindowDimensions(window.path);
974
+ return sum + (dimension.area || 0);
975
+ }, 0);
976
+ }
977
+ // Subtract window area from wall area
978
+ wallArea = Math.max(0, wallArea - totalWindowArea);
979
+ }
868
980
  // Create wall label
869
981
  let wallMaterial;
870
982
  if (metadata && metadata.walls[i] && metadata.walls[i].material)
@@ -879,14 +991,9 @@ export class BufferGeometry {
879
991
  z: (startPoint.z + endPoint.z) / 2
880
992
  };
881
993
  const direction = new THREE.Vector3(endPoint.x - startPoint.x, endPoint.y - startPoint.y, endPoint.z - startPoint.z).normalize();
882
- // Calculate the normal vector to the wall
883
- const up = new THREE.Vector3(0, 1, 0);
884
- const wallNormal = new THREE.Vector3().crossVectors(direction, up).normalize();
885
- // For flat walls, if the normal is close to zero (wall is vertical along Y),
886
- if (wallNormal.lengthSq() < 0.001) {
887
- // Wall is perfectly vertical, use a default normal
888
- wallNormal.set(1, 0, 0);
889
- }
994
+ // Calculate the normal vector to the wall based on polygon winding order
995
+ // Negate to keep labels inside, remove the negate to render all labels outside
996
+ const wallNormal = this.calculateWallNormal(i, startPoint, endPoint).negate();
890
997
  // Negation to position labels on the original side of the wall
891
998
  // wallNormal.negate();
892
999
  const edgeLength = direction.length();
@@ -975,7 +1082,7 @@ export class BufferGeometry {
975
1082
  is_deleted: wallDeleted
976
1083
  },
977
1084
  index: i,
978
- area: wallDimensions.area,
1085
+ area: wallArea,
979
1086
  width: wallDimensions.width,
980
1087
  perimeter: wallDimensions.perimeter,
981
1088
  wall_height: WALL_HEIGHT,
@@ -1045,8 +1152,12 @@ export class BufferGeometry {
1045
1152
  depthWrite: false
1046
1153
  }));
1047
1154
  windowMesh.name = windows[i].uuid ? `${windows[i].uuid}_window` : `window-${i}`;
1155
+ const outlineGeometry = new THREE.EdgesGeometry(windowGeometry);
1156
+ const outlineMaterial = new THREE.LineBasicMaterial({ color: this.inputs.windowOutlineColor, linewidth: 3 });
1157
+ const outlineMesh = new THREE.LineSegments(outlineGeometry, outlineMaterial);
1158
+ windowMesh.add(outlineMesh);
1048
1159
  // Add window center label if material is defined
1049
- if (windows[i].material) {
1160
+ if (windows[i].material || windows[i].name) {
1050
1161
  try {
1051
1162
  let twiceSignedArea = 0;
1052
1163
  let centroidU = 0;
@@ -1071,9 +1182,13 @@ export class BufferGeometry {
1071
1182
  centerU = sum.x / shapePoints2D.length;
1072
1183
  centerV = sum.y / shapePoints2D.length;
1073
1184
  }
1074
- // Create window label canvas
1075
- const windowLabel = windows[i].name ? `${windows[i].name}_${windows[i].material}` : `Window ${i}_${windows[i].material}`;
1076
- const windowCanvas = this.createLabelCanvas(windowLabel);
1185
+ // Calculate window area using the projected 2D coordinates
1186
+ const windowDimension = this.calculateWindowDimensions(windows[i].path);
1187
+ let windowLabelText = windows[i].name ? `${windows[i].name}` : windowMesh.name;
1188
+ windowLabelText = windows[i].material ? `${windowLabelText}_${windows[i].material}: ${windowDimension.area.toFixed(2)}m²` : `${windowLabelText}: ${windowDimension.area.toFixed(2)}m²`;
1189
+ log.info("windowLabelText ", windowLabelText);
1190
+ //const windowLabel = windows[i].name ? `${windows[i].name}_${windows[i].material}` : `Window ${i}_${windows[i].material}`
1191
+ const windowCanvas = this.createLabelCanvas(windowLabelText);
1077
1192
  const windowArea = Math.abs(twiceSignedArea * 0.5);
1078
1193
  const labelWidth = Math.max(0.5, Math.min(2, Math.sqrt(Math.max(0.0001, windowArea))));
1079
1194
  const labelHeight = labelWidth / 4;
package/lib/types.d.ts CHANGED
@@ -461,6 +461,7 @@ export interface ComponentOptions {
461
461
  drawingMode?: string | undefined;
462
462
  targetIndex?: number | undefined;
463
463
  targetUUID?: string | undefined;
464
+ deductWindowFromWallArea?: boolean | undefined;
464
465
  }
465
466
  export interface VectorCoords {
466
467
  object_position: Vector3;
@@ -762,6 +763,7 @@ export declare enum SPACE_EVENTS {
762
763
  SCREEN_SHARE_HOST_END_SESSION = "SCREEN_SHARE_HOST_END_SESSION",
763
764
  SCREEN_SHARE_GUEST_LEAVE_SESSION = "SCREEN_SHARE_GUEST_LEAVE_SESSION",
764
765
  SCREEN_SHARE_BACK_USER_LIST_PANE = "SCREEN_SHARE_BACK_USER_LIST_PANE",
766
+ SCREEN_SHARE_TERMINATED = "SCREEN_SHARE_TERMINATED",
765
767
  PIPE_INIT = "PIPE_INIT",
766
768
  PIPE_CATEGORY_REMOVED = "PIPE_CATEGORY_REMOVED",
767
769
  PIPE_CATEGORY_SAVED = "PIPE_CATEGORY_SAVED",
package/lib/types.js CHANGED
@@ -124,6 +124,7 @@ export var SPACE_EVENTS;
124
124
  SPACE_EVENTS["SCREEN_SHARE_HOST_END_SESSION"] = "SCREEN_SHARE_HOST_END_SESSION";
125
125
  SPACE_EVENTS["SCREEN_SHARE_GUEST_LEAVE_SESSION"] = "SCREEN_SHARE_GUEST_LEAVE_SESSION";
126
126
  SPACE_EVENTS["SCREEN_SHARE_BACK_USER_LIST_PANE"] = "SCREEN_SHARE_BACK_USER_LIST_PANE";
127
+ SPACE_EVENTS["SCREEN_SHARE_TERMINATED"] = "SCREEN_SHARE_TERMINATED";
127
128
  // PIPE
128
129
  SPACE_EVENTS["PIPE_INIT"] = "PIPE_INIT";
129
130
  SPACE_EVENTS["PIPE_CATEGORY_REMOVED"] = "PIPE_CATEGORY_REMOVED";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "architwin",
3
- "version": "1.14.9",
3
+ "version": "1.14.11",
4
4
  "description": "ArchiTwin Library for Matterport",
5
5
  "main": "./lib/architwin.js",
6
6
  "types": "./lib/architwin.d.ts",
@@ -2054,7 +2054,8 @@ dialog#at-screen-share-request-modal::backdrop {
2054
2054
 
2055
2055
  .at_screen_share_request_message {
2056
2056
  font-size: 24px;
2057
- font-weight: bold;
2057
+ font-weight: 700;
2058
+ color: #263646ef !important;
2058
2059
  padding: none !important;
2059
2060
  margin: none !important;
2060
2061
  }