@sequent-org/ifc-viewer 1.2.4-ci.53.0 → 1.2.4-ci.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/IfcViewer.js +44 -15
- package/src/main.js +4 -4
- package/src/styles-local.css +48 -1
- package/src/ui/CardPlacementController.js +3 -835
- package/src/ui/LabelPlacementController.js +1178 -0
- package/src/viewer/Viewer.js +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sequent-org/ifc-viewer",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.2.4-ci.
|
|
4
|
+
"version": "1.2.4-ci.55.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "IFC 3D model viewer component for web applications - fully self-contained with local IFCLoader",
|
|
7
7
|
"main": "src/index.js",
|
package/src/IfcViewer.js
CHANGED
|
@@ -22,7 +22,7 @@ import { TdsModelLoader } from "./model-loading/loaders/TdsModelLoader.js";
|
|
|
22
22
|
import { StlModelLoader } from "./model-loading/loaders/StlModelLoader.js";
|
|
23
23
|
import { DaeModelLoader } from "./model-loading/loaders/DaeModelLoader.js";
|
|
24
24
|
import { ThreeDmModelLoader } from "./model-loading/loaders/ThreeDmModelLoader.js";
|
|
25
|
-
import {
|
|
25
|
+
import { LabelPlacementController } from "./ui/LabelPlacementController.js";
|
|
26
26
|
import './style.css';
|
|
27
27
|
|
|
28
28
|
|
|
@@ -83,6 +83,7 @@ export class IfcViewer {
|
|
|
83
83
|
this.viewer = null;
|
|
84
84
|
this.ifcService = null;
|
|
85
85
|
this.ifcTreeView = null;
|
|
86
|
+
this.labelPlacement = null;
|
|
86
87
|
this.cardPlacement = null;
|
|
87
88
|
/** @type {ModelLoaderRegistry|null} */
|
|
88
89
|
this.modelLoaders = null;
|
|
@@ -311,10 +312,11 @@ export class IfcViewer {
|
|
|
311
312
|
this.ifcService = null;
|
|
312
313
|
}
|
|
313
314
|
|
|
314
|
-
if (this.
|
|
315
|
-
try { this.
|
|
316
|
-
this.
|
|
315
|
+
if (this.labelPlacement) {
|
|
316
|
+
try { this.labelPlacement.dispose(); } catch (_) {}
|
|
317
|
+
this.labelPlacement = null;
|
|
317
318
|
}
|
|
319
|
+
this.cardPlacement = null;
|
|
318
320
|
|
|
319
321
|
if (this.viewer) {
|
|
320
322
|
this.viewer.dispose();
|
|
@@ -361,21 +363,46 @@ export class IfcViewer {
|
|
|
361
363
|
}
|
|
362
364
|
|
|
363
365
|
/**
|
|
364
|
-
* Устанавливает метки
|
|
366
|
+
* Устанавливает метки извне.
|
|
365
367
|
* @param {Array<{id: (number|string), localPoint: {x:number,y:number,z:number}, sceneState: object}>} items
|
|
366
368
|
*/
|
|
367
|
-
|
|
368
|
-
if (!this.
|
|
369
|
-
this.
|
|
369
|
+
setLabelMarkers(items) {
|
|
370
|
+
if (!this.labelPlacement) return;
|
|
371
|
+
this.labelPlacement.setLabelMarkers(items);
|
|
370
372
|
}
|
|
371
373
|
|
|
372
374
|
/**
|
|
373
|
-
* Возвращает текущие
|
|
375
|
+
* Возвращает текущие метки.
|
|
374
376
|
* @returns {Array<{id: (number|string), localPoint: {x:number,y:number,z:number}, sceneState: object}>}
|
|
375
377
|
*/
|
|
378
|
+
getLabelMarkers() {
|
|
379
|
+
if (!this.labelPlacement) return [];
|
|
380
|
+
return this.labelPlacement.getLabelMarkers();
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Программно выбирает метку по id.
|
|
385
|
+
* @param {number|string|null} id
|
|
386
|
+
*/
|
|
387
|
+
selectLabel(id) {
|
|
388
|
+
if (!this.labelPlacement) return;
|
|
389
|
+
this.labelPlacement.selectLabel(id);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @deprecated используйте setLabelMarkers
|
|
394
|
+
*/
|
|
395
|
+
setCardMarkers(items) {
|
|
396
|
+
if (!this.labelPlacement) return;
|
|
397
|
+
this.labelPlacement.setCardMarkers(items);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* @deprecated используйте getLabelMarkers
|
|
402
|
+
*/
|
|
376
403
|
getCardMarkers() {
|
|
377
|
-
if (!this.
|
|
378
|
-
return this.
|
|
404
|
+
if (!this.labelPlacement) return [];
|
|
405
|
+
return this.labelPlacement.getCardMarkers();
|
|
379
406
|
}
|
|
380
407
|
|
|
381
408
|
/**
|
|
@@ -534,12 +561,14 @@ export class IfcViewer {
|
|
|
534
561
|
this.viewer = new Viewer(this.elements.viewerContainer);
|
|
535
562
|
this.viewer.init();
|
|
536
563
|
|
|
537
|
-
// В пакете включаем UI "
|
|
538
|
-
// кнопка "+ Добавить
|
|
564
|
+
// В пакете включаем UI "меток" по умолчанию:
|
|
565
|
+
// кнопка "+ Добавить метку" + режим постановки меток + сохранение/восстановление состояния.
|
|
539
566
|
try {
|
|
540
|
-
this.
|
|
567
|
+
this.labelPlacement = new LabelPlacementController({ viewer: this.viewer, container: this.elements.viewerContainer, logger: console });
|
|
568
|
+
this.cardPlacement = this.labelPlacement;
|
|
541
569
|
} catch (e) {
|
|
542
|
-
console.warn('IfcViewer:
|
|
570
|
+
console.warn('IfcViewer: LabelPlacementController init failed', e);
|
|
571
|
+
this.labelPlacement = null;
|
|
543
572
|
this.cardPlacement = null;
|
|
544
573
|
}
|
|
545
574
|
}
|
package/src/main.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Viewer } from "./viewer/Viewer.js";
|
|
|
3
3
|
import { IfcService } from "./ifc/IfcService.js";
|
|
4
4
|
import { IfcTreeView } from "./ifc/IfcTreeView.js";
|
|
5
5
|
import { ModelLoaderRegistry } from "./model-loading/ModelLoaderRegistry.js";
|
|
6
|
-
import {
|
|
6
|
+
import { LabelPlacementController } from "./ui/LabelPlacementController.js";
|
|
7
7
|
import { IfcModelLoader } from "./model-loading/loaders/IfcModelLoader.js";
|
|
8
8
|
import { FbxModelLoader } from "./model-loading/loaders/FbxModelLoader.js";
|
|
9
9
|
import { GltfModelLoader } from "./model-loading/loaders/GltfModelLoader.js";
|
|
@@ -19,8 +19,8 @@ if (app) {
|
|
|
19
19
|
const viewer = new Viewer(app);
|
|
20
20
|
viewer.init();
|
|
21
21
|
|
|
22
|
-
// UI: режим постановки
|
|
23
|
-
const
|
|
22
|
+
// UI: режим постановки меток по клику на модель
|
|
23
|
+
const labelPlacement = new LabelPlacementController({ viewer, container: app, logger: console });
|
|
24
24
|
|
|
25
25
|
// ===== Диагностика (включается через query-параметры) =====
|
|
26
26
|
// ?debugViewer=1 -> window.__viewer = viewer
|
|
@@ -680,7 +680,7 @@ if (app) {
|
|
|
680
680
|
import.meta.hot.dispose(() => {
|
|
681
681
|
ifc.dispose();
|
|
682
682
|
viewer.dispose();
|
|
683
|
-
try {
|
|
683
|
+
try { labelPlacement.dispose(); } catch (_) {}
|
|
684
684
|
});
|
|
685
685
|
}
|
|
686
686
|
}
|
package/src/styles-local.css
CHANGED
|
@@ -110,7 +110,8 @@
|
|
|
110
110
|
.duration-300 { transition-duration: 300ms; }
|
|
111
111
|
.pointer-events-none { pointer-events: none; }
|
|
112
112
|
|
|
113
|
-
/* === IFC
|
|
113
|
+
/* === IFC LABEL MARKERS (UI overlay) === */
|
|
114
|
+
.ifc-label-add-btn,
|
|
114
115
|
.ifc-card-add-btn {
|
|
115
116
|
position: absolute;
|
|
116
117
|
left: 12px;
|
|
@@ -130,10 +131,13 @@
|
|
|
130
131
|
backdrop-filter: blur(6px);
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
.ifc-label-add-btn:hover,
|
|
133
135
|
.ifc-card-add-btn:hover {
|
|
134
136
|
background: rgba(255, 255, 255, 0.98);
|
|
135
137
|
}
|
|
136
138
|
|
|
139
|
+
.ifc-label-ghost,
|
|
140
|
+
.ifc-label-marker,
|
|
137
141
|
.ifc-card-ghost,
|
|
138
142
|
.ifc-card-marker {
|
|
139
143
|
position: absolute;
|
|
@@ -144,10 +148,12 @@
|
|
|
144
148
|
will-change: transform;
|
|
145
149
|
}
|
|
146
150
|
|
|
151
|
+
.ifc-label-ghost,
|
|
147
152
|
.ifc-card-ghost {
|
|
148
153
|
display: none;
|
|
149
154
|
}
|
|
150
155
|
|
|
156
|
+
.ifc-label-dot,
|
|
151
157
|
.ifc-card-dot {
|
|
152
158
|
width: 18px;
|
|
153
159
|
height: 18px;
|
|
@@ -157,6 +163,7 @@
|
|
|
157
163
|
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
|
|
158
164
|
}
|
|
159
165
|
|
|
166
|
+
.ifc-label-num,
|
|
160
167
|
.ifc-card-num {
|
|
161
168
|
position: absolute;
|
|
162
169
|
left: 0;
|
|
@@ -172,6 +179,7 @@
|
|
|
172
179
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
|
|
173
180
|
}
|
|
174
181
|
|
|
182
|
+
.ifc-label-marker,
|
|
175
183
|
.ifc-card-marker {
|
|
176
184
|
width: 18px;
|
|
177
185
|
height: 18px;
|
|
@@ -180,11 +188,50 @@
|
|
|
180
188
|
}
|
|
181
189
|
|
|
182
190
|
/* Клик ловим на контейнере метки, дочерние элементы пусть не перехватывают */
|
|
191
|
+
.ifc-label-marker .ifc-label-dot,
|
|
192
|
+
.ifc-label-marker .ifc-label-num,
|
|
183
193
|
.ifc-card-marker .ifc-card-dot,
|
|
184
194
|
.ifc-card-marker .ifc-card-num {
|
|
185
195
|
pointer-events: none;
|
|
186
196
|
}
|
|
187
197
|
|
|
198
|
+
.ifc-label-marker--active .ifc-label-dot,
|
|
199
|
+
.ifc-card-marker--active .ifc-card-dot {
|
|
200
|
+
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.95), 0 0 0 4px rgba(37, 99, 235, 0.95);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* === LABEL CONTEXT MENU === */
|
|
204
|
+
.ifc-label-menu {
|
|
205
|
+
position: absolute;
|
|
206
|
+
z-index: 10000;
|
|
207
|
+
display: block;
|
|
208
|
+
min-width: 140px;
|
|
209
|
+
padding: 6px;
|
|
210
|
+
background: rgba(255, 255, 255, 0.98);
|
|
211
|
+
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
212
|
+
border-radius: 10px;
|
|
213
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
|
|
214
|
+
backdrop-filter: blur(6px);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.ifc-label-menu-item {
|
|
218
|
+
width: 100%;
|
|
219
|
+
display: block;
|
|
220
|
+
text-align: left;
|
|
221
|
+
border: none;
|
|
222
|
+
background: transparent;
|
|
223
|
+
color: #1f2937;
|
|
224
|
+
font-size: 12px;
|
|
225
|
+
font-weight: 600;
|
|
226
|
+
padding: 6px 8px;
|
|
227
|
+
border-radius: 6px;
|
|
228
|
+
cursor: pointer;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.ifc-label-menu-item:hover {
|
|
232
|
+
background: rgba(37, 99, 235, 0.12);
|
|
233
|
+
}
|
|
234
|
+
|
|
188
235
|
/* === NAVBAR COMPONENT === */
|
|
189
236
|
.navbar {
|
|
190
237
|
display: flex;
|