@sequent-org/ifc-viewer 1.2.4-ci.23.0 → 1.2.4-ci.25.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sequent-org/ifc-viewer",
3
3
  "private": false,
4
- "version": "1.2.4-ci.23.0",
4
+ "version": "1.2.4-ci.25.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
@@ -293,8 +293,16 @@ export class IfcViewer {
293
293
  // Основная разметка просмотрщика
294
294
  const html = `
295
295
  <div class="ifc-viewer-container" style="width: 100%; height: 100%; position: relative; display: flex; flex-direction: column; border:0px red solid;">
296
+ <!-- Прелоадер -->
297
+ <div id="ifcPreloader" class="absolute inset-0 bg-base-100 flex items-center justify-center z-50">
298
+ <div class="text-center">
299
+ <span class="loading loading-spinner loading-lg"></span>
300
+ <div class="mt-2 text-sm opacity-70">Загрузка модели...</div>
301
+ </div>
302
+ </div>
303
+
296
304
  <!-- Верхняя панель управления -->
297
- <div id="ifcToolbar" class="d-flex px-4" style="border:0px red solid; width: 250px; position: absolute; z-index: 1000; justify-content:space-between; bottom: 5px; left: calc(50% - 125px); ">
305
+ <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); ">
298
306
 
299
307
  <div class="navbar-end flex gap-2">
300
308
 
@@ -311,36 +319,7 @@ export class IfcViewer {
311
319
  </div>
312
320
 
313
321
  </div>
314
- </div>
315
-
316
- <!-- Слайдеры секущих плоскостей (изначально скрыты) -->
317
- <div id="ifcClipControls" class="bg-base-200 px-4 py-2 border-b border-base-300" style="display: ${this.options.showToolbar ? 'none' : 'none'};">
318
- <div class="flex items-center gap-4 text-sm">
319
- <!-- Слайдер X -->
320
- <div id="ifcClipXControl" class="flex items-center gap-2" style="display: none;">
321
- <span class="w-12">Clip X:</span>
322
- <input type="range" id="ifcClipXRange" class="range range-sm flex-1" min="0" max="1" step="0.01" value="0.5">
323
- </div>
324
- <!-- Слайдер Y -->
325
- <div id="ifcClipYControl" class="flex items-center gap-2" style="display: none;">
326
- <span class="w-12">Clip Y:</span>
327
- <input type="range" id="ifcClipYRange" class="range range-sm flex-1" min="0" max="1" step="0.01" value="0.5">
328
- </div>
329
- <!-- Слайдер Z -->
330
- <div id="ifcClipZControl" class="flex items-center gap-2" style="display: none;">
331
- <span class="w-12">Clip Z:</span>
332
- <input type="range" id="ifcClipZRange" class="range range-sm flex-1" min="0" max="1" step="0.01" value="0.5">
333
- </div>
334
- </div>
335
- </div>
336
-
337
- <!-- Прелоадер -->
338
- <div id="ifcPreloader" class="absolute inset-0 bg-base-100 flex items-center justify-center z-50">
339
- <div class="text-center">
340
- <span class="loading loading-spinner loading-lg"></span>
341
- <div class="mt-2 text-sm opacity-70">Загрузка модели...</div>
342
- </div>
343
- </div>
322
+ </div>
344
323
 
345
324
  <!-- Основной контейнер просмотрщика -->
346
325
  <div id="ifcViewerMain" class="w-full flex-1 relative"></div>
@@ -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: 0xd32f2f, transparent: true, opacity: this.faceOpacity }), // +X (red)
34
- new THREE.MeshBasicMaterial({ color: 0x7f0000, transparent: true, opacity: this.faceOpacity }), // -X (dark red)
35
- new THREE.MeshBasicMaterial({ color: 0x388e3c, transparent: true, opacity: this.faceOpacity }), // +Y (green)
36
- new THREE.MeshBasicMaterial({ color: 0x1b5e20, transparent: true, opacity: this.faceOpacity }), // -Y (dark green)
37
- new THREE.MeshBasicMaterial({ color: 0x1976d2, transparent: true, opacity: this.faceOpacity }), // +Z (blue)
38
- new THREE.MeshBasicMaterial({ color: 0x0d47a1, transparent: true, opacity: this.faceOpacity }), // -Z (dark blue)
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: 0x111111, depthTest: true });
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,21 @@ 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.textContent = '⌂';
93
+ this.homeBtn.innerHTML = `
94
+ <svg fill="#000000" width="20px" height="20px" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" class="icon">
95
+ <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"/>
96
+ </svg>
97
+ `;
94
98
  this.homeBtn.style.position = 'absolute';
95
- this.homeBtn.style.zIndex = '40';
96
- this.homeBtn.style.width = '28px';
97
- this.homeBtn.style.height = '28px';
98
- this.homeBtn.style.lineHeight = '28px';
99
- this.homeBtn.style.textAlign = 'center';
99
+ this.homeBtn.style.zIndex = '40';
100
+ this.homeBtn.style.width = '30px';
101
+ this.homeBtn.style.height = '30px';
100
102
  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.border = '0px solid rgba(255,255,255,0.1)';
104
+ this.homeBtn.style.background = 'rgba(0, 0, 0, 0.05)';
103
105
  this.homeBtn.style.color = '#fff';
104
106
  this.homeBtn.style.cursor = 'pointer';
105
- this.homeBtn.style.userSelect = 'none';
106
- this.homeBtn.style.font = '14px/28px system-ui, sans-serif';
107
+ this.homeBtn.style.userSelect = 'none';
107
108
  // Позиция задаётся в renderOverlay относительно текущего размера
108
109
  this.homeBtn.addEventListener('click', () => { try { this.onHome && this.onHome(); } catch(_) {} });
109
110
  try { this.container.appendChild(this.homeBtn); } catch(_) {}
@@ -177,15 +178,15 @@ export class NavCube {
177
178
 
178
179
  // Позиционируем кнопку Home слева от куба
179
180
  if (this.homeBtn) {
180
- this.homeBtn.style.top = `${this.marginPx + 2}px`;
181
- this.homeBtn.style.left = `${Math.max(2, fullW - this.marginPx - vpSize - 32)}px`;
181
+ this.homeBtn.style.top = `${this.marginPx + 20}px`;
182
+ this.homeBtn.style.left = `${Math.max(2, fullW - this.marginPx - vpSize - 60)}px`;
182
183
  }
183
184
  }
184
185
 
185
186
  // ================= Подписи граней =================
186
187
  #addFaceLabels() {
187
188
  const makeFaceTexture = (text) => {
188
- const size = 512; // квадрат для равномерности
189
+ const size = Math.floor(512 / 0.98); // квадрат для равномерности
189
190
  const canvas = document.createElement('canvas');
190
191
  canvas.width = size; canvas.height = size;
191
192
  const ctx = canvas.getContext('2d');
@@ -193,12 +194,13 @@ export class NavCube {
193
194
  ctx.clearRect(0, 0, size, size);
194
195
  // Чёрный крупный текст по центру
195
196
  ctx.fillStyle = '#000';
196
- // Уменьшаем шрифт примерно в 1.2 раза относительно прошлого (0.42 -> ~0.35)
197
- const fontPx = Math.floor(size * 0.35);
197
+ // Уменьшаем шрифт для лучшего размещения длинных слов
198
+ const fontPx = Math.floor(size * 0.2); // было 0.35, стало 0.25
198
199
  ctx.font = `bold ${fontPx}px sans-serif`;
199
200
  ctx.textAlign = 'center';
200
201
  ctx.textBaseline = 'middle';
201
202
  ctx.fillText(text.toUpperCase(), size / 2, size / 2);
203
+
202
204
  const tex = new THREE.CanvasTexture(canvas);
203
205
  tex.minFilter = THREE.LinearFilter;
204
206
  tex.magFilter = THREE.LinearFilter;
@@ -209,8 +211,8 @@ export class NavCube {
209
211
  const tex = makeFaceTexture(text);
210
212
  if (!tex) return null;
211
213
  const mat = new THREE.MeshBasicMaterial({ map: tex, transparent: true, depthTest: true, depthWrite: false });
212
- // Уменьшаем паддинги плашки: максимально приближаем к размеру грани
213
- const plane = new THREE.Mesh(new THREE.PlaneGeometry(0.995, 0.995), mat);
214
+ // Уменьшаем размер плашки для лучшего размещения текста
215
+ const plane = new THREE.Mesh(new THREE.PlaneGeometry(0.98, 0.98), mat);
214
216
  // Ориентируем плоскость, чтобы нормаль смотрела как normal
215
217
  const q = new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 0, 1), normal);
216
218
  plane.setRotationFromQuaternion(q);