bc-model-viewer 1.7.22 → 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/
|
|
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.
|
|
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
|
-
<
|
|
423
|
-
|
|
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
|
-
|
|
426
|
-
|
|
427
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|