bc-model-viewer 1.7.23 → 1.7.31

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.
@@ -192,6 +192,15 @@
192
192
  font-weight: 600;
193
193
  color: #495057;
194
194
  font-size: 14px;
195
+ flex: 1;
196
+ }
197
+
198
+ .tree-folder-checkbox {
199
+ width: 18px;
200
+ height: 18px;
201
+ margin-right: 8px;
202
+ cursor: pointer;
203
+ accent-color: #667eea;
195
204
  }
196
205
 
197
206
  .tree-layer-item {
@@ -285,6 +294,7 @@
285
294
  <ul style="margin: 0; padding-left: 20px; font-size: 13px; color: #666; line-height: 1.8;">
286
295
  <li>切换"树形视图"、"列表视图"和"DFC视图"查看图层</li>
287
296
  <li>在树形视图中,点击文件夹图标可展开/折叠</li>
297
+ <li>文件夹复选框:可批量控制该文件夹下所有图层的可见性(半选状态表示部分可见)</li>
288
298
  <li>DFC视图:输入 DFC key (如 "dfc-architecture") 查看特定类型的图层树形结构</li>
289
299
  <li>勾选/取消勾选复选框来切换图层可见性</li>
290
300
  <li>使用搜索框快速查找图层(支持文件夹路径搜索)</li>
@@ -315,7 +325,7 @@
315
325
 
316
326
  // 加载测试模型
317
327
  try {
318
- await viewer.loadZipAsync('./dgz/ob.dgz')
328
+ await viewer.loadZipAsync('./dgz/2号楼.dgz')
319
329
  console.log('模型加载成功')
320
330
 
321
331
  // 模型加载完成后,初始化图层列表
@@ -368,7 +378,7 @@
368
378
  layerList.innerHTML = '<div class="empty-state">请输入 DFC key 并点击"加载 DFC 树形结构"</div>'
369
379
  return
370
380
  }
371
- const dfcTree = viewer.layerManager.getDfcTreeStructure(currentDfcKey)
381
+ const dfcTree = viewer.layerManager.getTreeStructureByPath(currentDfcKey)
372
382
  if (dfcTree.length === 0) {
373
383
  layerList.innerHTML = `<div class="empty-state">未找到匹配的 DFC 图层 (key: ${currentDfcKey})</div>`
374
384
  return
@@ -403,6 +413,36 @@
403
413
  }
404
414
  }
405
415
 
416
+ // 获取文件夹下所有图层节点
417
+ function getAllLayerNodesFromFolder(folderNode) {
418
+ const layerNodes = []
419
+ if (folderNode.children) {
420
+ folderNode.children.forEach(child => {
421
+ if (child.type === 'layer') {
422
+ layerNodes.push(child)
423
+ } else if (child.type === 'folder') {
424
+ layerNodes.push(...getAllLayerNodesFromFolder(child))
425
+ }
426
+ })
427
+ }
428
+ return layerNodes
429
+ }
430
+
431
+ // 计算文件夹的复选框状态
432
+ function getFolderCheckboxState(folderNode) {
433
+ const layerNodes = getAllLayerNodesFromFolder(folderNode)
434
+ if (layerNodes.length === 0) return { checked: false, indeterminate: false }
435
+
436
+ const visibleCount = layerNodes.filter(n => n.layer && n.layer.visible !== false).length
437
+ const allVisible = visibleCount === layerNodes.length
438
+ const noneVisible = visibleCount === 0
439
+
440
+ return {
441
+ checked: allVisible,
442
+ indeterminate: !allVisible && !noneVisible
443
+ }
444
+ }
445
+
406
446
  // 渲染树形视图
407
447
  function renderTreeView(nodes, filterText = '', parentPath = '', parentContainer = null) {
408
448
  const container = parentContainer || document.getElementById('layerList')
@@ -416,16 +456,32 @@
416
456
  const hasMatch = filterText === '' || nodeMatchesFilter(node, filterText, true)
417
457
 
418
458
  if (filterText === '' || hasMatch) {
459
+ // 计算文件夹复选框状态
460
+ const checkboxState = getFolderCheckboxState(node)
419
461
  const folderDiv = document.createElement('div')
420
462
  folderDiv.className = 'tree-folder'
463
+ folderDiv.setAttribute('data-folder-path', currentPath)
464
+
465
+ const checkboxId = `folder-checkbox-${currentPath.replace(/\//g, '-')}`
421
466
  folderDiv.innerHTML = `
422
- <span class="tree-folder-icon ${isExpanded ? '' : 'collapsed'}">▶</span>
423
- <span class="tree-folder-name">📁 ${node.name}</span>
467
+ <input type="checkbox"
468
+ id="${checkboxId}"
469
+ class="tree-folder-checkbox"
470
+ ${checkboxState.checked ? 'checked' : ''}
471
+ onchange="toggleFolderLayers('${currentPath}', this.checked)"
472
+ onclick="event.stopPropagation()">
473
+ <span class="tree-folder-icon ${isExpanded ? '' : 'collapsed'}"
474
+ onclick="event.stopPropagation(); toggleFolder('${currentPath}')">▶</span>
475
+ <span class="tree-folder-name"
476
+ onclick="event.stopPropagation(); toggleFolder('${currentPath}')">📁 ${node.name}</span>
424
477
  `
425
- folderDiv.onclick = (e) => {
426
- e.stopPropagation()
427
- toggleFolder(currentPath)
478
+
479
+ // 设置半选状态
480
+ const checkbox = folderDiv.querySelector(`#${checkboxId}`)
481
+ if (checkbox) {
482
+ checkbox.indeterminate = checkboxState.indeterminate
428
483
  }
484
+
429
485
  container.appendChild(folderDiv)
430
486
 
431
487
  // 渲染子节点
@@ -528,7 +584,7 @@
528
584
  }
529
585
 
530
586
  // 切换文件夹展开/折叠
531
- function toggleFolder(path) {
587
+ window.toggleFolder = function (path) {
532
588
  if (expandedFolders.has(path)) {
533
589
  expandedFolders.delete(path)
534
590
  } else {
@@ -537,6 +593,55 @@
537
593
  renderLayerList()
538
594
  }
539
595
 
596
+ // 切换文件夹下所有图层的可见性
597
+ window.toggleFolderLayers = function (folderPath, visible) {
598
+ // 找到对应的文件夹节点
599
+ const tree = currentView === 'dfc' && currentDfcKey
600
+ ? viewer.layerManager.getTreeStructureByPath(currentDfcKey)
601
+ : viewer.layerManager.getTreeStructure()
602
+
603
+ const folderNode = findFolderNodeByPath(tree, folderPath)
604
+ if (!folderNode) return
605
+
606
+ // 获取文件夹下所有图层节点
607
+ const layerNodes = getAllLayerNodesFromFolder(folderNode)
608
+
609
+ // 更新所有图层的可见性
610
+ layerNodes.forEach(layerNode => {
611
+ if (layerNode.layer && layerNode.layerIndex !== undefined) {
612
+ layerNode.layer.visible = visible
613
+ }
614
+ })
615
+
616
+ // 更新模型显示
617
+ viewer.updateMeshVisibleByLayer()
618
+
619
+ // 更新UI
620
+ renderLayerList()
621
+ updateLayerStats()
622
+
623
+ // 更新所有文件夹复选框状态(包括父文件夹)
624
+ updateFolderCheckboxes()
625
+ }
626
+
627
+ // 根据路径查找文件夹节点
628
+ function findFolderNodeByPath(nodes, targetPath, parentPath = '') {
629
+ for (const node of nodes) {
630
+ if (node.type === 'folder') {
631
+ const currentPath = parentPath ? `${parentPath}/${node.name}` : node.name
632
+ if (currentPath === targetPath) {
633
+ return node
634
+ }
635
+ // 递归查找子节点
636
+ if (node.children) {
637
+ const found = findFolderNodeByPath(node.children, targetPath, currentPath)
638
+ if (found) return found
639
+ }
640
+ }
641
+ }
642
+ return null
643
+ }
644
+
540
645
  // 切换视图模式
541
646
  window.switchView = function (view) {
542
647
  currentView = view
@@ -586,7 +691,7 @@
586
691
 
587
692
  if (currentView === 'dfc' && currentDfcKey) {
588
693
  // DFC 视图:显示匹配的图层统计
589
- const dfcTree = viewer.layerManager.getDfcTreeStructure(currentDfcKey)
694
+ const dfcTree = viewer.layerManager.getTreeStructureByPath(currentDfcKey)
590
695
  const dfcLayers = getAllLayersFromTree(dfcTree)
591
696
  const total = dfcLayers.length
592
697
  const visible = dfcLayers.filter(l => l.visible !== false).length
@@ -645,9 +750,43 @@
645
750
  const checkbox = item.querySelector('input[type="checkbox"]')
646
751
  if (checkbox) checkbox.checked = visible
647
752
  })
753
+
754
+ // 更新父文件夹的复选框状态
755
+ updateFolderCheckboxes()
648
756
  }
649
757
  }
650
758
 
759
+ // 更新所有文件夹复选框的状态
760
+ function updateFolderCheckboxes() {
761
+ const tree = currentView === 'dfc' && currentDfcKey
762
+ ? viewer.layerManager.getTreeStructureByPath(currentDfcKey)
763
+ : viewer.layerManager.getTreeStructure()
764
+
765
+ updateFolderCheckboxRecursive(tree, '')
766
+ }
767
+
768
+ // 递归更新文件夹复选框状态
769
+ function updateFolderCheckboxRecursive(nodes, parentPath) {
770
+ nodes.forEach(node => {
771
+ if (node.type === 'folder') {
772
+ const currentPath = parentPath ? `${parentPath}/${node.name}` : node.name
773
+ const checkboxState = getFolderCheckboxState(node)
774
+ const checkboxId = `folder-checkbox-${currentPath.replace(/\//g, '-')}`
775
+ const checkbox = document.getElementById(checkboxId)
776
+
777
+ if (checkbox) {
778
+ checkbox.checked = checkboxState.checked
779
+ checkbox.indeterminate = checkboxState.indeterminate
780
+ }
781
+
782
+ // 递归更新子文件夹
783
+ if (node.children) {
784
+ updateFolderCheckboxRecursive(node.children, currentPath)
785
+ }
786
+ }
787
+ })
788
+ }
789
+
651
790
  // 兼容旧版本的函数
652
791
  window.toggleLayerVisibility = function (index, visible) {
653
792
  toggleLayerVisibilityByIndex(index, visible)
@@ -705,7 +844,7 @@
705
844
  // 如果有 DFC key,也打印 DFC 树形结构
706
845
  if (currentDfcKey) {
707
846
  console.log(`=== DFC 树形结构 (key: ${currentDfcKey}) ===`)
708
- console.log(viewer.layerManager.getDfcTreeStructure(currentDfcKey))
847
+ console.log(viewer.layerManager.getTreeStructureByPath(currentDfcKey))
709
848
  }
710
849
 
711
850
  // 打印所有有 path 属性的图层(用于查找可用的 DFC key)
@@ -128,13 +128,11 @@
128
128
  // 加载测试模型 - 请根据实际情况修改模型路径
129
129
  try {
130
130
  // 尝试加载默认模型,如果失败会显示错误信息
131
- // await viewer.loadZipAsync('../../../assets/dgz/49F酒店室内.dgz');
132
- await viewer.loadZipAsync('../../../assets/dgz/地下室管综2.dgz');
133
- console.log('模型加载成功');
131
+ await viewer.loadZipAsync('../../../assets/new.dgz');
132
+ // await viewer.loadZipAsync('../../../assets/dgz/地下室管综2.dgz');
134
133
 
135
134
  // 模型加载完成后,检查是否有内置场景
136
135
  console.log('模型中的场景:', viewer.scenePageManager.pages);
137
- console.log('场景数量:', viewer.scenePageManager.pages.length);
138
136
 
139
137
  // 设置场景页面事件监听
140
138
  setupScenePageEvents();
@@ -155,7 +153,6 @@
155
153
 
156
154
  // 监听页面切换开始事件
157
155
  scenePageManager.addEventListener('pageChangeStart', (event) => {
158
- console.log('PAGE_CHANGE_START', `开始切换到场景: ${event.page.name}`);
159
156
  });
160
157
 
161
158
  // 监听页面切换进度事件
@@ -165,20 +162,16 @@
165
162
  'cameraPositioned': '相机位置设置完成'
166
163
  };
167
164
  const stageDesc = stageDescriptions[event.stage] || event.stage;
168
- console.log('PAGE_CHANGE_PROGRESS', `进度: ${stageDesc}`);
169
165
  });
170
166
 
171
167
  // 监听页面切换完成事件
172
168
  scenePageManager.addEventListener('pageChangeComplete', (event) => {
173
- console.log('PAGE_CHANGE_COMPLETE', `成功切换到场景: ${event.page?.name || '未知'}`);
174
169
  });
175
170
 
176
171
  // 监听页面切换错误事件
177
172
  scenePageManager.addEventListener('pageChangeError', (event) => {
178
- console.log('PAGE_CHANGE_ERROR', `切换失败: ${event.error.message || '未知错误'}`);
179
173
  });
180
174
 
181
- console.log('已设置场景页面管理器事件监听器');
182
175
  }
183
176
 
184
177
  // 加载并显示模型中的场景
@@ -219,8 +212,6 @@
219
212
 
220
213
  // 显示第一个场景的详细信息
221
214
  displaySceneDetails(modelScenes[0]);
222
-
223
- console.log('已加载并显示模型中的所有场景');
224
215
  }
225
216
 
226
217
  // 显示场景详细信息
@@ -275,10 +266,6 @@
275
266
  window.getModelScenes = getModelScenes;
276
267
  window.getSceneByName = getSceneByName;
277
268
  window.loadAndDisplayModelScenes = loadAndDisplayModelScenes;
278
-
279
- console.log('场景页面管理器演示已加载');
280
- console.log('可用场景:', viewer.scenePageManager.getAllSceneNames());
281
- console.log('模型中的场景详情:', viewer.scenePageManager.pages);
282
269
  </script>
283
270
  </body>
284
271
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bc-model-viewer",
3
- "version": "1.7.23",
3
+ "version": "1.7.31",
4
4
  "main": "./dist/bc-model-viewer.min.js",
5
5
  "module": "./dist/bc-model-viewer.min.js",
6
6
  "description": "A model viewer",