@sequent-org/ifc-viewer 1.2.4-ci.24.0 → 1.2.4-ci.26.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 +3 -13
- package/src/styles-local.css +62 -2
- package/src/viewer/NavCube.js +21 -28
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.26.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
|
@@ -13,18 +13,8 @@
|
|
|
13
13
|
import { Viewer } from "./viewer/Viewer.js";
|
|
14
14
|
import { IfcService } from "./ifc/IfcService.js";
|
|
15
15
|
import { IfcTreeView } from "./ifc/IfcTreeView.js";
|
|
16
|
+
import './style.css';
|
|
16
17
|
|
|
17
|
-
// Загружаем стили при импорте IfcViewer
|
|
18
|
-
if (typeof window !== 'undefined' && !document.querySelector('style[data-ifc-viewer]')) {
|
|
19
|
-
import('./style.css').then(() => {
|
|
20
|
-
// Добавляем маркер, что стили загружены
|
|
21
|
-
const style = document.createElement('style');
|
|
22
|
-
style.setAttribute('data-ifc-viewer', 'loaded');
|
|
23
|
-
document.head.appendChild(style);
|
|
24
|
-
}).catch(error => {
|
|
25
|
-
console.warn('IfcViewer: не удалось загрузить стили:', error.message);
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
18
|
|
|
29
19
|
export class IfcViewer {
|
|
30
20
|
/**
|
|
@@ -302,7 +292,7 @@ export class IfcViewer {
|
|
|
302
292
|
</div>
|
|
303
293
|
|
|
304
294
|
<!-- Верхняя панель управления -->
|
|
305
|
-
<div id="ifcToolbar" class="d-flex px-4" style="border:0px red solid; width: 250px; position: absolute; z-index:
|
|
295
|
+
<div id="ifcToolbar" class="d-flex px-4" style="border:0px red solid; width: 250px; position: absolute; z-index: 60; justify-content:space-between; bottom: 10px; left: calc(50% - 125px); ">
|
|
306
296
|
|
|
307
297
|
<div class="navbar-end flex gap-2">
|
|
308
298
|
|
|
@@ -315,7 +305,7 @@ export class IfcViewer {
|
|
|
315
305
|
<div class="join">
|
|
316
306
|
<button class="btn btn-sm join-item" id="ifcClipX" style="margin-right:2px"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" class="MuiSvgIcon-root MuiSvgIcon-fontSizeLarge" focusable="false" viewBox="0 0 24 24" aria-hidden="true"><path d="M9.6 3v9.07l3.87-1.72a2 2 0 01.81-.17 2.08 2.08 0 011.77 3.09 1.09 1.09 0 01-.56.56l-4.36 1.94L21.6 21V9z"></path><path d="M4.74 15.33l9.14-4.07a1 1 0 011.32.51 1 1 0 01-.51 1.32l-9.14 4.07 4 1.52L9 20l-6.6-2.53 2.53-6.6 1.32.51z"></path></svg></button>
|
|
317
307
|
<button class="btn btn-sm join-item" id="ifcClipZ" style="margin-right:2px"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" class="MuiSvgIcon-root MuiSvgIcon-fontSizeLarge" focusable="false" viewBox="0 0 24 24" aria-hidden="true"><path d="M8 13.82a1.09 1.09 0 01-.56-.56 2.08 2.08 0 011.78-3.09 2 2 0 01.81.17l3.87 1.72V3l-11 6v12l9.54-5.2z"></path><path d="M17.24 11.37l1.32-.51 2.53 6.6L14.5 20l-.5-1.32 4-1.52-9.18-4.07a1 1 0 01-.51-1.32 1 1 0 011.32-.51l9.14 4.07z"></path></svg></button>
|
|
318
|
-
<button class="btn btn-sm join-item" id="ifcClipY" style="margin-right:
|
|
308
|
+
<button class="btn btn-sm join-item" id="ifcClipY" style="margin-right:0px"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" class="MuiSvgIcon-root MuiSvgIcon-fontSizeLarge" focusable="false" viewBox="0 0 24 24" aria-hidden="true"><path d="M14.25 11.18v3.52A1.87 1.87 0 0111 15.88a1 1 0 01-.32-.72V11.1l-9 4.5L12.45 21l9.9-5.4z"></path><path d="M8.85 8.4L8 7.5 12.45 3 17 7.5l-.9.9-2.7-2.7v9a.9.9 0 01-.9.9.9.9 0 01-.9-.9v-9z"></path></svg></button>
|
|
319
309
|
</div>
|
|
320
310
|
|
|
321
311
|
</div>
|
package/src/styles-local.css
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
|
|
17
17
|
/* === CSS VARIABLES (THEME COLORS) === */
|
|
18
18
|
.ifc-viewer-container {
|
|
19
|
-
--color-primary: #
|
|
20
|
-
--color-primary-hover: #
|
|
19
|
+
--color-primary: #80D8FF;
|
|
20
|
+
--color-primary-hover: #80D8FF;
|
|
21
21
|
--color-secondary: #64748b;
|
|
22
22
|
--color-secondary-hover: #475569;
|
|
23
23
|
--color-neutral: #374151;
|
|
@@ -412,3 +412,63 @@
|
|
|
412
412
|
.text-orange-600 { color: #ea580c; }
|
|
413
413
|
.text-gray-600 { color: #4b5563; }
|
|
414
414
|
.text-gray-500 { color: #6b7280; }
|
|
415
|
+
|
|
416
|
+
/* === TOOLBAR BUTTONS SHADOWS === */
|
|
417
|
+
#ifcToolbar .join {
|
|
418
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.25) !important;
|
|
419
|
+
transition: box-shadow 0.2s ease !important;
|
|
420
|
+
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/* #ifcToolbar .btn:hover {
|
|
424
|
+
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3) !important;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
#ifcToolbar .btn:active {
|
|
428
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2) !important;
|
|
429
|
+
} */
|
|
430
|
+
|
|
431
|
+
/* === HOME BUTTON === */
|
|
432
|
+
.nav-cube-home-btn {
|
|
433
|
+
/* Позиционирование */
|
|
434
|
+
position: absolute;
|
|
435
|
+
z-index: 40;
|
|
436
|
+
|
|
437
|
+
/* Стили как у .btn .btn-sm */
|
|
438
|
+
display: inline-flex;
|
|
439
|
+
align-items: center;
|
|
440
|
+
justify-content: center;
|
|
441
|
+
border-radius: var(--border-radius);
|
|
442
|
+
height: 2rem;
|
|
443
|
+
min-height: 2rem;
|
|
444
|
+
width: 2rem;
|
|
445
|
+
padding: 0;
|
|
446
|
+
font-size: 0.75rem;
|
|
447
|
+
font-weight: 600;
|
|
448
|
+
text-decoration: none;
|
|
449
|
+
border: 1px solid transparent;
|
|
450
|
+
cursor: pointer;
|
|
451
|
+
user-select: none;
|
|
452
|
+
transition-property: color, background-color, border-color, box-shadow;
|
|
453
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
454
|
+
transition-duration: 200ms;
|
|
455
|
+
background-color: var(--color-base-200);
|
|
456
|
+
color: var(--color-neutral);
|
|
457
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.nav-cube-home-btn:hover {
|
|
461
|
+
background-color: var(--color-base-300);
|
|
462
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.nav-cube-home-btn:active {
|
|
466
|
+
background-color: var(--color-base-300);
|
|
467
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.nav-cube-home-btn svg {
|
|
471
|
+
fill: #000000;
|
|
472
|
+
width: 18px;
|
|
473
|
+
height: 18px;
|
|
474
|
+
}
|
package/src/viewer/NavCube.js
CHANGED
|
@@ -30,12 +30,12 @@ export class NavCube {
|
|
|
30
30
|
// Полупрозрачный куб с окрашенными сторонами (+X/-X, +Y/-Y, +Z/-Z)
|
|
31
31
|
const geom = new THREE.BoxGeometry(1, 1, 1);
|
|
32
32
|
const mats = [
|
|
33
|
-
new THREE.MeshBasicMaterial({ color:
|
|
34
|
-
new THREE.MeshBasicMaterial({ color:
|
|
35
|
-
new THREE.MeshBasicMaterial({ color:
|
|
36
|
-
new THREE.MeshBasicMaterial({ color:
|
|
37
|
-
new THREE.MeshBasicMaterial({ color:
|
|
38
|
-
new THREE.MeshBasicMaterial({ color:
|
|
33
|
+
new THREE.MeshBasicMaterial({ color: 0x80CBC4, transparent: true, opacity: this.faceOpacity }), // +X (сзади - зеленый)
|
|
34
|
+
new THREE.MeshBasicMaterial({ color: 0xA5D6A7, transparent: true, opacity: this.faceOpacity }), // -X (спереди - зеленый)
|
|
35
|
+
new THREE.MeshBasicMaterial({ color: 0xFF8A65, transparent: true, opacity: this.faceOpacity }), // +Y (верх - красный )
|
|
36
|
+
new THREE.MeshBasicMaterial({ color: 0xEF9A9A, transparent: true, opacity: this.faceOpacity }), // -Y (низ - красный)
|
|
37
|
+
new THREE.MeshBasicMaterial({ color: 0x90CAF9, transparent: true, opacity: this.faceOpacity }), // +Z (справа - синий)
|
|
38
|
+
new THREE.MeshBasicMaterial({ color: 0x9FA8DA, transparent: true, opacity: this.faceOpacity }), // -Z (слева - синий)
|
|
39
39
|
];
|
|
40
40
|
this.cube = new THREE.Mesh(geom, mats);
|
|
41
41
|
this.cube.name = "nav-cube";
|
|
@@ -53,7 +53,7 @@ export class NavCube {
|
|
|
53
53
|
|
|
54
54
|
// Рёбра для читабельности
|
|
55
55
|
const edges = new THREE.EdgesGeometry(geom, 1);
|
|
56
|
-
const lineMat = new THREE.LineBasicMaterial({ color:
|
|
56
|
+
const lineMat = new THREE.LineBasicMaterial({ color: 0xEEEEEE, depthTest: true });
|
|
57
57
|
this.cubeEdges = new THREE.LineSegments(edges, lineMat);
|
|
58
58
|
this.cubeEdges.renderOrder = 999;
|
|
59
59
|
this.cube.add(this.cubeEdges);
|
|
@@ -90,20 +90,12 @@ export class NavCube {
|
|
|
90
90
|
this.homeBtn = document.createElement('button');
|
|
91
91
|
this.homeBtn.type = 'button';
|
|
92
92
|
this.homeBtn.title = 'Home';
|
|
93
|
-
this.homeBtn.
|
|
94
|
-
this.homeBtn.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.homeBtn.style.textAlign = 'center';
|
|
100
|
-
this.homeBtn.style.borderRadius = '6px';
|
|
101
|
-
this.homeBtn.style.border = '1px solid rgba(255,255,255,0.4)';
|
|
102
|
-
this.homeBtn.style.background = 'rgba(0,0,0,0.45)';
|
|
103
|
-
this.homeBtn.style.color = '#fff';
|
|
104
|
-
this.homeBtn.style.cursor = 'pointer';
|
|
105
|
-
this.homeBtn.style.userSelect = 'none';
|
|
106
|
-
this.homeBtn.style.font = '14px/28px system-ui, sans-serif';
|
|
93
|
+
this.homeBtn.className = 'nav-cube-home-btn';
|
|
94
|
+
this.homeBtn.innerHTML = `
|
|
95
|
+
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon">
|
|
96
|
+
<path d="M946.5 505L534.6 93.4a31.93 31.93 0 0 0-45.2 0L77.5 505c-12 12-18.8 28.3-18.8 45.3 0 35.3 28.7 64 64 64h43.4V908c0 17.7 14.3 32 32 32H448V716h112v224h265.9c17.7 0 32-14.3 32-32V614.3h43.4c17 0 33.3-6.7 45.3-18.8 24.9-25 24.9-65.5-.1-90.5z"/>
|
|
97
|
+
</svg>
|
|
98
|
+
`;
|
|
107
99
|
// Позиция задаётся в renderOverlay относительно текущего размера
|
|
108
100
|
this.homeBtn.addEventListener('click', () => { try { this.onHome && this.onHome(); } catch(_) {} });
|
|
109
101
|
try { this.container.appendChild(this.homeBtn); } catch(_) {}
|
|
@@ -177,15 +169,15 @@ export class NavCube {
|
|
|
177
169
|
|
|
178
170
|
// Позиционируем кнопку Home слева от куба
|
|
179
171
|
if (this.homeBtn) {
|
|
180
|
-
this.homeBtn.style.top = `${this.marginPx +
|
|
181
|
-
this.homeBtn.style.left = `${Math.max(2, fullW - this.marginPx - vpSize -
|
|
172
|
+
this.homeBtn.style.top = `${this.marginPx + 20}px`;
|
|
173
|
+
this.homeBtn.style.left = `${Math.max(2, fullW - this.marginPx - vpSize - 60)}px`;
|
|
182
174
|
}
|
|
183
175
|
}
|
|
184
176
|
|
|
185
177
|
// ================= Подписи граней =================
|
|
186
178
|
#addFaceLabels() {
|
|
187
179
|
const makeFaceTexture = (text) => {
|
|
188
|
-
const size = 512; // квадрат для равномерности
|
|
180
|
+
const size = Math.floor(512 / 0.98); // квадрат для равномерности
|
|
189
181
|
const canvas = document.createElement('canvas');
|
|
190
182
|
canvas.width = size; canvas.height = size;
|
|
191
183
|
const ctx = canvas.getContext('2d');
|
|
@@ -193,12 +185,13 @@ export class NavCube {
|
|
|
193
185
|
ctx.clearRect(0, 0, size, size);
|
|
194
186
|
// Чёрный крупный текст по центру
|
|
195
187
|
ctx.fillStyle = '#000';
|
|
196
|
-
// Уменьшаем шрифт
|
|
197
|
-
const fontPx = Math.floor(size * 0.
|
|
188
|
+
// Уменьшаем шрифт для лучшего размещения длинных слов
|
|
189
|
+
const fontPx = Math.floor(size * 0.2); // было 0.35, стало 0.25
|
|
198
190
|
ctx.font = `bold ${fontPx}px sans-serif`;
|
|
199
191
|
ctx.textAlign = 'center';
|
|
200
192
|
ctx.textBaseline = 'middle';
|
|
201
193
|
ctx.fillText(text.toUpperCase(), size / 2, size / 2);
|
|
194
|
+
|
|
202
195
|
const tex = new THREE.CanvasTexture(canvas);
|
|
203
196
|
tex.minFilter = THREE.LinearFilter;
|
|
204
197
|
tex.magFilter = THREE.LinearFilter;
|
|
@@ -209,8 +202,8 @@ export class NavCube {
|
|
|
209
202
|
const tex = makeFaceTexture(text);
|
|
210
203
|
if (!tex) return null;
|
|
211
204
|
const mat = new THREE.MeshBasicMaterial({ map: tex, transparent: true, depthTest: true, depthWrite: false });
|
|
212
|
-
// Уменьшаем
|
|
213
|
-
const plane = new THREE.Mesh(new THREE.PlaneGeometry(0.
|
|
205
|
+
// Уменьшаем размер плашки для лучшего размещения текста
|
|
206
|
+
const plane = new THREE.Mesh(new THREE.PlaneGeometry(0.98, 0.98), mat);
|
|
214
207
|
// Ориентируем плоскость, чтобы нормаль смотрела как normal
|
|
215
208
|
const q = new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 0, 1), normal);
|
|
216
209
|
plane.setRotationFromQuaternion(q);
|