bc-model-viewer 1.7.23 → 1.7.45
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.
|
@@ -24,7 +24,12 @@
|
|
|
24
24
|
<button onclick="tool.clear()" class="danger">清除所有</button>
|
|
25
25
|
</div>
|
|
26
26
|
<div class="control-group">
|
|
27
|
-
<button onclick="
|
|
27
|
+
<button onclick="tool.updateAnnotationsVisibility(20)">显示所有批注</button>
|
|
28
|
+
<button onclick="hideAllAnnotations()">隐藏所有批注</button>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="control-group">
|
|
31
|
+
<button onclick="loadTestAnnotations()">加载测试批注</button>
|
|
32
|
+
<button onclick="console.log(tool.getAnnotations())">打印批注数据</button>
|
|
28
33
|
</div>
|
|
29
34
|
<div class="control-group">
|
|
30
35
|
<p style="font-size: 12px; color: #888; margin-top: 10px;">
|
|
@@ -57,8 +62,8 @@
|
|
|
57
62
|
})
|
|
58
63
|
|
|
59
64
|
// 加载测试模型
|
|
60
|
-
await viewer.loadZipAsync('../../assets/dgz/建筑.dgz')
|
|
61
|
-
|
|
65
|
+
// await viewer.loadZipAsync('../../assets/dgz/建筑.dgz')
|
|
66
|
+
await viewer.loadZipAsync('../../assets/new.dgz')
|
|
62
67
|
|
|
63
68
|
// AnnotationTool 已在 Viewer 构造函数中自动初始化
|
|
64
69
|
// 可以通过 viewer.annotationTool 访问
|
|
@@ -68,6 +73,63 @@
|
|
|
68
73
|
|
|
69
74
|
window.tool = tool
|
|
70
75
|
window.viewer = viewer
|
|
76
|
+
|
|
77
|
+
// 辅助函数:隐藏所有批注
|
|
78
|
+
window.hideAllAnnotations = function() {
|
|
79
|
+
if (!tool || !tool.annotations) return;
|
|
80
|
+
|
|
81
|
+
tool.annotations.forEach((annotation) => {
|
|
82
|
+
annotation.line.visible = false;
|
|
83
|
+
annotation.label.visible = false;
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// 辅助函数:加载测试批注数据
|
|
88
|
+
window.loadTestAnnotations = function() {
|
|
89
|
+
if (!tool) return;
|
|
90
|
+
|
|
91
|
+
// 测试批注数据(使用简单的坐标)
|
|
92
|
+
const testAnnotations = [
|
|
93
|
+
{
|
|
94
|
+
point: [0, 0, 0],
|
|
95
|
+
label: "测试批注 1",
|
|
96
|
+
viewport: {
|
|
97
|
+
x: 100,
|
|
98
|
+
y: 100,
|
|
99
|
+
width: 800,
|
|
100
|
+
height: 600
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
point: [1, 1, 1],
|
|
105
|
+
label: "测试批注 2",
|
|
106
|
+
viewport: {
|
|
107
|
+
x: 100,
|
|
108
|
+
y: 100,
|
|
109
|
+
width: 800,
|
|
110
|
+
height: 600
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
point: [-1, -1, 0],
|
|
115
|
+
label: "测试批注 3",
|
|
116
|
+
viewport: {
|
|
117
|
+
x: 100,
|
|
118
|
+
y: 100,
|
|
119
|
+
width: 800,
|
|
120
|
+
height: 600
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
tool.loadAnnotationsFromData(testAnnotations);
|
|
127
|
+
console.log('测试批注加载成功');
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error('加载测试批注失败:', error);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
71
133
|
</script>
|
|
72
134
|
|
|
73
135
|
</body>
|
|
@@ -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('
|
|
328
|
+
await viewer.loadZipAsync('../../../assets/new.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)
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>属性查看工具演示 - Bc-model-viewer</title>
|
|
8
|
+
<link rel="stylesheet" href="common-styles.css">
|
|
9
|
+
<style>
|
|
10
|
+
.demo {
|
|
11
|
+
position: absolute;
|
|
12
|
+
top: 20px;
|
|
13
|
+
left: 20px;
|
|
14
|
+
z-index: 1000;
|
|
15
|
+
background: rgba(255, 255, 255, 0.95);
|
|
16
|
+
backdrop-filter: blur(10px);
|
|
17
|
+
border-radius: 12px;
|
|
18
|
+
padding: 20px;
|
|
19
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
|
20
|
+
max-width: 350px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.control-group {
|
|
24
|
+
margin-bottom: 15px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.control-group h3 {
|
|
28
|
+
margin: 0 0 10px 0;
|
|
29
|
+
color: #333;
|
|
30
|
+
font-size: 16px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.btn {
|
|
34
|
+
background: #377ee8;
|
|
35
|
+
color: white;
|
|
36
|
+
border: none;
|
|
37
|
+
padding: 8px 12px;
|
|
38
|
+
border-radius: 4px;
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
font-size: 14px;
|
|
41
|
+
transition: background 0.2s;
|
|
42
|
+
margin-right: 8px;
|
|
43
|
+
margin-bottom: 8px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.btn:hover {
|
|
47
|
+
background: #2a6bd1;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.btn.active {
|
|
51
|
+
background: #1e4f9e;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.btn:disabled {
|
|
55
|
+
background: #aaa;
|
|
56
|
+
cursor: not-allowed;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.instructions {
|
|
60
|
+
background: rgba(55, 126, 232, 0.1);
|
|
61
|
+
border: 1px solid rgba(55, 126, 232, 0.3);
|
|
62
|
+
border-radius: 4px;
|
|
63
|
+
padding: 15px;
|
|
64
|
+
margin-bottom: 15px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.instructions h4 {
|
|
68
|
+
margin: 0 0 10px 0;
|
|
69
|
+
color: #377ee8;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.instructions ul {
|
|
73
|
+
margin: 0;
|
|
74
|
+
padding-left: 20px;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.instructions li {
|
|
78
|
+
margin-bottom: 5px;
|
|
79
|
+
color: #666;
|
|
80
|
+
font-size: 13px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.model-info {
|
|
84
|
+
background: rgba(0, 0, 0, 0.05);
|
|
85
|
+
border-radius: 4px;
|
|
86
|
+
padding: 15px;
|
|
87
|
+
margin-bottom: 15px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.model-info h4 {
|
|
91
|
+
margin: 0 0 10px 0;
|
|
92
|
+
color: #377ee8;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.info-item {
|
|
96
|
+
display: flex;
|
|
97
|
+
justify-content: space-between;
|
|
98
|
+
margin-bottom: 5px;
|
|
99
|
+
font-size: 13px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.info-label {
|
|
103
|
+
color: #666;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.info-value {
|
|
107
|
+
color: #333;
|
|
108
|
+
font-weight: 500;
|
|
109
|
+
}
|
|
110
|
+
</style>
|
|
111
|
+
</head>
|
|
112
|
+
|
|
113
|
+
<body>
|
|
114
|
+
<div id="container"></div>
|
|
115
|
+
<a href="index.html" class="back-button">返回示例列表</a>
|
|
116
|
+
|
|
117
|
+
<div class="demo">
|
|
118
|
+
<h2>🔍 属性查看工具演示</h2>
|
|
119
|
+
<p>点击模型上的对象查看其属性信息,包括基本属性和用户自定义数据。</p>
|
|
120
|
+
|
|
121
|
+
<div class="instructions">
|
|
122
|
+
<h4>使用说明</h4>
|
|
123
|
+
<ul>
|
|
124
|
+
<li>点击"激活工具"按钮启用属性查看功能</li>
|
|
125
|
+
<li>点击模型上的任意对象查看其属性</li>
|
|
126
|
+
<li>属性信息将显示在右侧面板中</li>
|
|
127
|
+
<li>点击空白区域可关闭属性面板</li>
|
|
128
|
+
<li>支持查看基本属性和用户自定义属性</li>
|
|
129
|
+
</ul>
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
<div class="control-group">
|
|
133
|
+
<h3>工具控制</h3>
|
|
134
|
+
<button id="activateBtn" class="btn">激活工具</button>
|
|
135
|
+
<button id="deactivateBtn" class="btn" disabled>停用工具</button>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<div class="control-group">
|
|
139
|
+
<h3>加载模型</h3>
|
|
140
|
+
<button id="loadModel1" class="btn">加载测试模型1</button>
|
|
141
|
+
<button id="loadModel2" class="btn">加载测试模型2</button>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<div class="model-info">
|
|
145
|
+
<h4>当前状态</h4>
|
|
146
|
+
<div class="info-item">
|
|
147
|
+
<span class="info-label">工具状态:</span>
|
|
148
|
+
<span id="toolStatus" class="info-value">未激活</span>
|
|
149
|
+
</div>
|
|
150
|
+
<div class="info-item">
|
|
151
|
+
<span class="info-label">已选择对象:</span>
|
|
152
|
+
<span id="selectedObject" class="info-value">无</span>
|
|
153
|
+
</div>
|
|
154
|
+
<div class="info-item">
|
|
155
|
+
<span class="info-label">模型加载:</span>
|
|
156
|
+
<span id="modelStatus" class="info-value">未加载</span>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<div class="control-group">
|
|
161
|
+
<p style="font-size: 12px; color: #888; margin-top: 10px;">
|
|
162
|
+
💡 使用提示:<br>
|
|
163
|
+
• 激活工具后,鼠标悬停在对象上会显示对象名称<br>
|
|
164
|
+
• 点击对象后,属性面板会显示在右上角<br>
|
|
165
|
+
• 支持查看位置、旋转、缩放等基本属性<br>
|
|
166
|
+
• 自动提取并显示对象的用户自定义数据<br>
|
|
167
|
+
• 点击空白区域或关闭按钮可隐藏属性面板
|
|
168
|
+
</p>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
<script type="module">
|
|
173
|
+
import { Viewer, PropertyViewerTool } from '../../index.ts'
|
|
174
|
+
|
|
175
|
+
const container = document.getElementById('container')
|
|
176
|
+
|
|
177
|
+
// 实例化 Viewer 对象
|
|
178
|
+
const viewer = new Viewer(container, {
|
|
179
|
+
load: {
|
|
180
|
+
cache: {
|
|
181
|
+
enabled: false
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
let propertyViewerTool = null
|
|
187
|
+
|
|
188
|
+
// 更新状态显示
|
|
189
|
+
function updateStatus() {
|
|
190
|
+
document.getElementById('toolStatus').textContent =
|
|
191
|
+
propertyViewerTool && propertyViewerTool.isActive ? '已激活' : '未激活'
|
|
192
|
+
|
|
193
|
+
document.getElementById('selectedObject').textContent =
|
|
194
|
+
propertyViewerTool && propertyViewerTool.selectedObject ?
|
|
195
|
+
(propertyViewerTool.selectedObject.name || propertyViewerTool.selectedObject.type) : '无'
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 激活属性查看工具
|
|
199
|
+
document.getElementById('activateBtn').addEventListener('click', () => {
|
|
200
|
+
if (!propertyViewerTool) {
|
|
201
|
+
propertyViewerTool = new PropertyViewerTool(viewer)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// 停用其他工具
|
|
205
|
+
// viewer.deactivateAllTools()
|
|
206
|
+
|
|
207
|
+
// 激活属性查看工具
|
|
208
|
+
propertyViewerTool.activate()
|
|
209
|
+
|
|
210
|
+
// 更新按钮状态
|
|
211
|
+
document.getElementById('activateBtn').disabled = true
|
|
212
|
+
document.getElementById('deactivateBtn').disabled = false
|
|
213
|
+
|
|
214
|
+
updateStatus()
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
// 停用属性查看工具
|
|
218
|
+
document.getElementById('deactivateBtn').addEventListener('click', () => {
|
|
219
|
+
if (propertyViewerTool) {
|
|
220
|
+
propertyViewerTool.deactivate()
|
|
221
|
+
|
|
222
|
+
// 更新按钮状态
|
|
223
|
+
document.getElementById('activateBtn').disabled = false
|
|
224
|
+
document.getElementById('deactivateBtn').disabled = true
|
|
225
|
+
|
|
226
|
+
updateStatus()
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
// 加载测试模型1
|
|
231
|
+
document.getElementById('loadModel1').addEventListener('click', async () => {
|
|
232
|
+
try {
|
|
233
|
+
// 加载测试模型
|
|
234
|
+
await viewer.loadZipAsync('../../assets/dgz/建筑.dgz')
|
|
235
|
+
document.getElementById('modelStatus').textContent = '模型1已加载'
|
|
236
|
+
|
|
237
|
+
// 为模型对象添加一些自定义属性用于测试
|
|
238
|
+
setTimeout(() => {
|
|
239
|
+
if (viewer.scene && viewer.scene.children.length > 0) {
|
|
240
|
+
viewer.scene.children.forEach((child, index) => {
|
|
241
|
+
// 添加一些测试用的用户数据
|
|
242
|
+
child.userData = {
|
|
243
|
+
material: 'Steel',
|
|
244
|
+
weight: '15kg',
|
|
245
|
+
manufacturer: 'Test Corp',
|
|
246
|
+
partNumber: `PN-${index + 1000}`,
|
|
247
|
+
description: '这是一个测试对象的描述信息'
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
}, 100)
|
|
252
|
+
|
|
253
|
+
} catch (error) {
|
|
254
|
+
console.error('加载模型失败:', error)
|
|
255
|
+
document.getElementById('modelStatus').textContent = '加载失败'
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
// 加载测试模型2
|
|
260
|
+
document.getElementById('loadModel2').addEventListener('click', async () => {
|
|
261
|
+
try {
|
|
262
|
+
// 加载另一个测试模型
|
|
263
|
+
await viewer.loadZipAsync('../../assets/dgz/样板间.dgz')
|
|
264
|
+
document.getElementById('modelStatus').textContent = '模型2已加载'
|
|
265
|
+
|
|
266
|
+
// 为模型对象添加不同的自定义属性
|
|
267
|
+
setTimeout(() => {
|
|
268
|
+
if (viewer.scene && viewer.scene.children.length > 0) {
|
|
269
|
+
viewer.scene.children.forEach((child, index) => {
|
|
270
|
+
child.userData = {
|
|
271
|
+
material: 'Aluminum',
|
|
272
|
+
weight: '8kg',
|
|
273
|
+
manufacturer: 'Demo Inc',
|
|
274
|
+
partNumber: `PN-${index + 2000}`,
|
|
275
|
+
color: 'Blue',
|
|
276
|
+
productionDate: '2024-01-15'
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
}
|
|
280
|
+
}, 100)
|
|
281
|
+
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.error('加载模型失败:', error)
|
|
284
|
+
document.getElementById('modelStatus').textContent = '加载失败'
|
|
285
|
+
}
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
// 初始状态更新
|
|
289
|
+
updateStatus()
|
|
290
|
+
|
|
291
|
+
// 暴露到全局对象方便调试
|
|
292
|
+
window.viewer = viewer
|
|
293
|
+
window.propertyViewerTool = propertyViewerTool
|
|
294
|
+
|
|
295
|
+
console.log('属性查看工具演示已初始化')
|
|
296
|
+
</script>
|
|
297
|
+
</body>
|
|
298
|
+
|
|
299
|
+
</html>
|