bc-model-viewer 1.7.15 → 1.7.18
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/dist/bc-model-viewer.min.js +1 -1
- package/examples/AnnotationTool.html +74 -0
- package/examples/AreaMeasureTool.html +19 -26
- package/examples/BasicModelLoad.html +66 -0
- package/examples/ChangeStyleDemo.html +3 -74
- package/examples/DistanceMeasureTool.html +19 -26
- package/examples/ExplosionDiagram.html +16 -21
- package/examples/FaceDistanceMeasureTool.html +19 -26
- package/examples/HUDLabelTool.html +19 -35
- package/examples/LineTool.html +76 -0
- package/examples/ModelClipperTool.html +15 -23
- package/examples/PencilTool.html +73 -0
- package/examples/PositionCameraTool.html +12 -21
- package/examples/ScenePageDemo.html +20 -49
- package/examples/SelectionZoomTool.html +12 -22
- package/examples/common-styles.css +173 -0
- package/examples/index.html +696 -36
- package/package.json +1 -1
- package/examples/ScenePageDemo.vue +0 -246
- package/examples/ScenePageDemoVue.html +0 -22
package/examples/index.html
CHANGED
|
@@ -1,67 +1,727 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html lang="
|
|
2
|
+
<html lang="zh-CN">
|
|
3
3
|
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="UTF-8">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<title>Bc-model-viewer
|
|
7
|
+
<title>Bc-model-viewer 示例导航</title>
|
|
8
8
|
<style>
|
|
9
|
-
|
|
9
|
+
* {
|
|
10
10
|
margin: 0;
|
|
11
|
+
padding: 0;
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
body {
|
|
16
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
17
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
18
|
+
min-height: 100vh;
|
|
19
|
+
padding: 20px;
|
|
20
|
+
color: #333;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.container {
|
|
24
|
+
max-width: 1200px;
|
|
25
|
+
margin: 0 auto;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
header {
|
|
29
|
+
text-align: center;
|
|
30
|
+
color: white;
|
|
31
|
+
margin-bottom: 40px;
|
|
32
|
+
padding: 30px 20px;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
header h1 {
|
|
36
|
+
font-size: 2.5em;
|
|
37
|
+
margin-bottom: 10px;
|
|
38
|
+
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
header p {
|
|
42
|
+
font-size: 1.1em;
|
|
43
|
+
opacity: 0.95;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.examples-grid {
|
|
47
|
+
display: grid;
|
|
48
|
+
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
|
49
|
+
gap: 20px;
|
|
50
|
+
margin-bottom: 40px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.example-card {
|
|
54
|
+
background: white;
|
|
55
|
+
border-radius: 12px;
|
|
56
|
+
padding: 25px;
|
|
57
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
58
|
+
transition: all 0.3s ease;
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.example-card:hover {
|
|
65
|
+
transform: translateY(-5px);
|
|
66
|
+
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.example-card h3 {
|
|
70
|
+
color: #667eea;
|
|
71
|
+
margin-bottom: 10px;
|
|
72
|
+
font-size: 1.3em;
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
gap: 8px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.example-card .icon {
|
|
79
|
+
font-size: 1.2em;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.example-card .description {
|
|
83
|
+
color: #666;
|
|
84
|
+
margin-bottom: 15px;
|
|
85
|
+
line-height: 1.6;
|
|
86
|
+
flex-grow: 1;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.example-card .tags {
|
|
90
|
+
display: flex;
|
|
91
|
+
flex-wrap: wrap;
|
|
92
|
+
gap: 6px;
|
|
93
|
+
margin-bottom: 15px;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.example-card .tag {
|
|
97
|
+
background: #f0f0f0;
|
|
98
|
+
color: #555;
|
|
99
|
+
padding: 4px 10px;
|
|
100
|
+
border-radius: 12px;
|
|
101
|
+
font-size: 0.85em;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.example-card .tag.tag-tool {
|
|
105
|
+
background: #e3f2fd;
|
|
106
|
+
color: #1976d2;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.example-card .tag.tag-demo {
|
|
110
|
+
background: #f3e5f5;
|
|
111
|
+
color: #7b1fa2;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.example-card .tag.tag-feature {
|
|
115
|
+
background: #e8f5e9;
|
|
116
|
+
color: #388e3c;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.example-card .link-button {
|
|
120
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
121
|
+
color: white;
|
|
122
|
+
border: none;
|
|
123
|
+
padding: 10px 20px;
|
|
124
|
+
border-radius: 6px;
|
|
125
|
+
cursor: pointer;
|
|
126
|
+
font-size: 0.95em;
|
|
127
|
+
font-weight: 500;
|
|
128
|
+
transition: all 0.3s ease;
|
|
129
|
+
text-decoration: none;
|
|
130
|
+
display: inline-block;
|
|
131
|
+
text-align: center;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.example-card .link-button:hover {
|
|
135
|
+
transform: scale(1.05);
|
|
136
|
+
box-shadow: 0 4px 8px rgba(102, 126, 234, 0.4);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.category-section {
|
|
140
|
+
margin-bottom: 50px;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.category-title {
|
|
144
|
+
color: white;
|
|
145
|
+
font-size: 1.8em;
|
|
146
|
+
margin-bottom: 20px;
|
|
147
|
+
padding-bottom: 10px;
|
|
148
|
+
border-bottom: 2px solid rgba(255, 255, 255, 0.3);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.footer {
|
|
152
|
+
text-align: center;
|
|
153
|
+
color: white;
|
|
154
|
+
padding: 30px 20px;
|
|
155
|
+
opacity: 0.9;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.footer a {
|
|
159
|
+
color: white;
|
|
160
|
+
text-decoration: underline;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@media (max-width: 768px) {
|
|
164
|
+
.examples-grid {
|
|
165
|
+
grid-template-columns: 1fr;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
header h1 {
|
|
169
|
+
font-size: 2em;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.category-title {
|
|
173
|
+
font-size: 1.5em;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.search-box {
|
|
178
|
+
max-width: 500px;
|
|
179
|
+
margin: 0 auto 60px;
|
|
11
180
|
position: relative;
|
|
12
181
|
}
|
|
13
182
|
|
|
14
|
-
.
|
|
183
|
+
.search-hint {
|
|
184
|
+
margin-top: 8px;
|
|
185
|
+
font-size: 0.85em;
|
|
186
|
+
color: rgba(255, 255, 255, 0.7);
|
|
187
|
+
text-align: center;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.search-hint kbd {
|
|
191
|
+
background: rgba(255, 255, 255, 0.2);
|
|
192
|
+
padding: 2px 6px;
|
|
193
|
+
border-radius: 3px;
|
|
194
|
+
font-family: monospace;
|
|
195
|
+
font-size: 0.9em;
|
|
196
|
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.search-box input {
|
|
200
|
+
width: 100%;
|
|
201
|
+
padding: 15px 45px 15px 20px;
|
|
202
|
+
border: none;
|
|
203
|
+
border-radius: 25px;
|
|
204
|
+
font-size: 1em;
|
|
205
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.search-box input:focus {
|
|
209
|
+
outline: none;
|
|
210
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.search-icon {
|
|
15
214
|
position: absolute;
|
|
16
|
-
|
|
17
|
-
top:
|
|
215
|
+
right: 15px;
|
|
216
|
+
top: 33%;
|
|
217
|
+
transform: translateY(-50%);
|
|
218
|
+
color: #999;
|
|
219
|
+
pointer-events: none;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* 搜索结果高亮样式 */
|
|
223
|
+
.highlight {
|
|
224
|
+
background: linear-gradient(120deg, #ffd700 0%, #ffed4e 100%);
|
|
225
|
+
padding: 2px 4px;
|
|
226
|
+
border-radius: 3px;
|
|
227
|
+
font-weight: 500;
|
|
228
|
+
color: #333;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* 搜索结果提示 */
|
|
232
|
+
#search-result {
|
|
233
|
+
animation: fadeIn 0.3s ease-in;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
@keyframes fadeIn {
|
|
237
|
+
from {
|
|
238
|
+
opacity: 0;
|
|
239
|
+
transform: translateY(-10px);
|
|
240
|
+
}
|
|
241
|
+
to {
|
|
242
|
+
opacity: 1;
|
|
243
|
+
transform: translateY(0);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* 加载动画 */
|
|
248
|
+
.loading {
|
|
249
|
+
display: inline-block;
|
|
250
|
+
width: 20px;
|
|
251
|
+
height: 20px;
|
|
252
|
+
border: 3px solid rgba(255, 255, 255, 0.3);
|
|
253
|
+
border-radius: 50%;
|
|
254
|
+
border-top-color: white;
|
|
255
|
+
animation: spin 0.8s ease-in-out infinite;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@keyframes spin {
|
|
259
|
+
to { transform: rotate(360deg); }
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* 无障碍优化 */
|
|
263
|
+
.example-card:focus {
|
|
264
|
+
outline: 3px solid rgba(255, 255, 255, 0.8);
|
|
265
|
+
outline-offset: 2px;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.link-button:focus {
|
|
269
|
+
outline: 2px solid white;
|
|
270
|
+
outline-offset: 2px;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* 平滑滚动 */
|
|
274
|
+
html {
|
|
275
|
+
scroll-behavior: smooth;
|
|
18
276
|
}
|
|
19
277
|
</style>
|
|
20
278
|
</head>
|
|
21
279
|
|
|
22
280
|
<body>
|
|
23
|
-
<div
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
281
|
+
<div class="container">
|
|
282
|
+
<header>
|
|
283
|
+
<h1>🚀 Bc-model-viewer</h1>
|
|
284
|
+
<p>3D 模型查看器示例导航</p>
|
|
285
|
+
</header>
|
|
286
|
+
|
|
287
|
+
<div class="search-box">
|
|
288
|
+
<input type="text" id="searchInput" placeholder="搜索示例... (按 / 聚焦搜索)"
|
|
289
|
+
aria-label="搜索示例">
|
|
290
|
+
<span class="search-icon">🔍</span>
|
|
291
|
+
<div class="search-hint">
|
|
292
|
+
快捷键: <kbd>/</kbd> 搜索 | <kbd>Esc</kbd> 清除 | <kbd>Ctrl+K</kbd> 快速搜索
|
|
293
|
+
</div>
|
|
294
|
+
</div>
|
|
295
|
+
|
|
296
|
+
<!-- 测量工具示例 -->
|
|
297
|
+
<section class="category-section">
|
|
298
|
+
<h2 class="category-title">📏 测量工具</h2>
|
|
299
|
+
<div class="examples-grid">
|
|
300
|
+
<div class="example-card" data-name="距离测量工具" data-desc="距离测量">
|
|
301
|
+
<h3><span class="icon">📐</span>距离测量工具</h3>
|
|
302
|
+
<div class="description">演示如何使用距离测量工具在3D场景中测量两点之间的距离。支持多点连续测量和标签编辑。</div>
|
|
303
|
+
<div class="tags">
|
|
304
|
+
<span class="tag tag-tool">测量工具</span>
|
|
305
|
+
<span class="tag tag-feature">距离计算</span>
|
|
306
|
+
</div>
|
|
307
|
+
<a href="DistanceMeasureTool.html" class="link-button">查看示例 →</a>
|
|
308
|
+
</div>
|
|
309
|
+
|
|
310
|
+
<div class="example-card" data-name="面积测量工具" data-desc="面积测量">
|
|
311
|
+
<h3><span class="icon">📊</span>面积测量工具</h3>
|
|
312
|
+
<div class="description">演示如何使用面积测量工具在模型表面测量区域面积。适用于平面和曲面测量。</div>
|
|
313
|
+
<div class="tags">
|
|
314
|
+
<span class="tag tag-tool">测量工具</span>
|
|
315
|
+
<span class="tag tag-feature">面积计算</span>
|
|
316
|
+
</div>
|
|
317
|
+
<a href="AreaMeasureTool.html" class="link-button">查看示例 →</a>
|
|
318
|
+
</div>
|
|
319
|
+
|
|
320
|
+
<div class="example-card" data-name="面面测量工具" data-desc="面面距离">
|
|
321
|
+
<h3><span class="icon">📏</span>面面测量工具</h3>
|
|
322
|
+
<div class="description">演示如何测量两个面之间的距离。适用于建筑和工程场景中的精确测量需求。</div>
|
|
323
|
+
<div class="tags">
|
|
324
|
+
<span class="tag tag-tool">测量工具</span>
|
|
325
|
+
<span class="tag tag-feature">面距离</span>
|
|
326
|
+
</div>
|
|
327
|
+
<a href="FaceDistanceMeasureTool.html" class="link-button">查看示例 →</a>
|
|
328
|
+
</div>
|
|
329
|
+
|
|
330
|
+
<div class="example-card" data-name="手绘线工具" data-desc="绘制线条">
|
|
331
|
+
<h3><span class="icon">✏️</span>手绘线工具</h3>
|
|
332
|
+
<div class="description">按住鼠标拖动绘制连续线条。支持吸附到模型表面,松开鼠标完成绘制。激活时禁用相机控制。</div>
|
|
333
|
+
<div class="tags">
|
|
334
|
+
<span class="tag tag-tool">绘制工具</span>
|
|
335
|
+
<span class="tag tag-feature">手绘线条</span>
|
|
336
|
+
<span class="tag tag-feature">表面吸附</span>
|
|
337
|
+
</div>
|
|
338
|
+
<a href="PencilTool.html" class="link-button">查看示例 →</a>
|
|
339
|
+
</div>
|
|
340
|
+
|
|
341
|
+
<div class="example-card" data-name="直线工具" data-desc="绘制直线">
|
|
342
|
+
<h3><span class="icon">📏</span>直线工具</h3>
|
|
343
|
+
<div class="description">点击两点绘制直线。支持吸附到模型表面,点击起点和终点完成绘制。激活时禁用相机控制。</div>
|
|
344
|
+
<div class="tags">
|
|
345
|
+
<span class="tag tag-tool">绘制工具</span>
|
|
346
|
+
<span class="tag tag-feature">直线绘制</span>
|
|
347
|
+
<span class="tag tag-feature">表面吸附</span>
|
|
348
|
+
</div>
|
|
349
|
+
<a href="LineTool.html" class="link-button">查看示例 →</a>
|
|
350
|
+
</div>
|
|
351
|
+
|
|
352
|
+
<div class="example-card" data-name="标注工具" data-desc="文本标注">
|
|
353
|
+
<h3><span class="icon">📝</span>标注工具</h3>
|
|
354
|
+
<div class="description">点击模型上的点作为锚点,再次点击确定文本位置,输入标注文字后按回车完成。支持删除功能。</div>
|
|
355
|
+
<div class="tags">
|
|
356
|
+
<span class="tag tag-tool">标注工具</span>
|
|
357
|
+
<span class="tag tag-feature">文本标注</span>
|
|
358
|
+
<span class="tag tag-feature">交互输入</span>
|
|
359
|
+
</div>
|
|
360
|
+
<a href="AnnotationTool.html" class="link-button">查看示例 →</a>
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
</section>
|
|
364
|
+
|
|
365
|
+
<!-- 样式和视觉效果示例 -->
|
|
366
|
+
<section class="category-section">
|
|
367
|
+
<h2 class="category-title">🎨 样式和视觉效果</h2>
|
|
368
|
+
<div class="examples-grid">
|
|
369
|
+
<div class="example-card" data-name="样式切换演示" data-desc="样式背景边线">
|
|
370
|
+
<h3><span class="icon">🎨</span>样式切换演示</h3>
|
|
371
|
+
<div class="description">演示如何切换不同的渲染样式,包括预设风格、环境光渲染、单色显示、透明度模式等。还支持自定义背景和边线颜色。</div>
|
|
372
|
+
<div class="tags">
|
|
373
|
+
<span class="tag tag-demo">样式演示</span>
|
|
374
|
+
<span class="tag tag-feature">背景渐变</span>
|
|
375
|
+
<span class="tag tag-feature">边线控制</span>
|
|
376
|
+
</div>
|
|
377
|
+
<a href="ChangeStyleDemo.html" class="link-button">查看示例 →</a>
|
|
378
|
+
</div>
|
|
379
|
+
|
|
380
|
+
<div class="example-card" data-name="模型爆炸" data-desc="爆炸图">
|
|
381
|
+
<h3><span class="icon">💥</span>模型爆炸图</h3>
|
|
382
|
+
<div class="description">演示如何创建模型爆炸效果,通过调整爆炸强度来分离和展示模型的不同部件,便于查看内部结构。</div>
|
|
383
|
+
<div class="tags">
|
|
384
|
+
<span class="tag tag-demo">动画效果</span>
|
|
385
|
+
<span class="tag tag-feature">爆炸展示</span>
|
|
386
|
+
</div>
|
|
387
|
+
<a href="ExplosionDiagram.html" class="link-button">查看示例 →</a>
|
|
388
|
+
</div>
|
|
389
|
+
</div>
|
|
390
|
+
</section>
|
|
391
|
+
|
|
392
|
+
<!-- 交互工具示例 -->
|
|
393
|
+
<section class="category-section">
|
|
394
|
+
<h2 class="category-title">🛠️ 交互工具</h2>
|
|
395
|
+
<div class="examples-grid">
|
|
396
|
+
<div class="example-card" data-name="标签工具" data-desc="HUD标签">
|
|
397
|
+
<h3><span class="icon">🏷️</span>HUD 标签工具</h3>
|
|
398
|
+
<div class="description">演示如何在3D场景中添加HTML标签。支持自定义标签内容、样式和位置,可以在模型上添加标注信息。</div>
|
|
399
|
+
<div class="tags">
|
|
400
|
+
<span class="tag tag-tool">标签工具</span>
|
|
401
|
+
<span class="tag tag-feature">HTML标注</span>
|
|
402
|
+
</div>
|
|
403
|
+
<a href="HUDLabelTool.html" class="link-button">查看示例 →</a>
|
|
404
|
+
</div>
|
|
405
|
+
|
|
406
|
+
<div class="example-card" data-name="剖切工具" data-desc="模型剖切">
|
|
407
|
+
<h3><span class="icon">✂️</span>模型剖切工具</h3>
|
|
408
|
+
<div class="description">演示如何使用剖切工具对模型进行切片查看。支持多个剖切面,可以从不同角度查看模型内部结构。</div>
|
|
409
|
+
<div class="tags">
|
|
410
|
+
<span class="tag tag-tool">剖切工具</span>
|
|
411
|
+
<span class="tag tag-feature">切片查看</span>
|
|
412
|
+
</div>
|
|
413
|
+
<a href="ModelClipperTool.html" class="link-button">查看示例 →</a>
|
|
414
|
+
</div>
|
|
415
|
+
|
|
416
|
+
<div class="example-card" data-name="第一人称漫游" data-desc="相机漫游">
|
|
417
|
+
<h3><span class="icon">👤</span>第一人称漫游</h3>
|
|
418
|
+
<div class="description">演示第一人称视角的相机漫游功能。支持WASD移动、鼠标视角控制,提供沉浸式的模型浏览体验。</div>
|
|
419
|
+
<div class="tags">
|
|
420
|
+
<span class="tag tag-tool">相机工具</span>
|
|
421
|
+
<span class="tag tag-feature">第一人称</span>
|
|
422
|
+
</div>
|
|
423
|
+
<a href="PositionCameraTool.html" class="link-button">查看示例 →</a>
|
|
424
|
+
</div>
|
|
425
|
+
|
|
426
|
+
<div class="example-card" data-name="框选放大" data-desc="选择缩放">
|
|
427
|
+
<h3><span class="icon">🔍</span>框选放大工具</h3>
|
|
428
|
+
<div class="description">演示如何使用框选工具来放大查看模型的特定区域。框选范围越小,放大倍数越大,适合查看细节。</div>
|
|
429
|
+
<div class="tags">
|
|
430
|
+
<span class="tag tag-tool">选择工具</span>
|
|
431
|
+
<span class="tag tag-feature">区域缩放</span>
|
|
432
|
+
</div>
|
|
433
|
+
<a href="SelectionZoomTool.html" class="link-button">查看示例 →</a>
|
|
434
|
+
</div>
|
|
435
|
+
</div>
|
|
436
|
+
</section>
|
|
437
|
+
|
|
438
|
+
<!-- 基础示例 -->
|
|
439
|
+
<section class="category-section">
|
|
440
|
+
<h2 class="category-title">📦 基础示例</h2>
|
|
441
|
+
<div class="examples-grid">
|
|
442
|
+
<div class="example-card" data-name="基础模型加载" data-desc="模型加载">
|
|
443
|
+
<h3><span class="icon">📦</span>基础模型加载</h3>
|
|
444
|
+
<div class="description">最简单的模型加载示例,演示如何在不使用任何工具的情况下加载和显示3D模型。适合作为入门示例和基础集成参考。</div>
|
|
445
|
+
<div class="tags">
|
|
446
|
+
<span class="tag tag-demo">基础示例</span>
|
|
447
|
+
<span class="tag tag-feature">模型加载</span>
|
|
448
|
+
<span class="tag tag-feature">入门教程</span>
|
|
449
|
+
</div>
|
|
450
|
+
<a href="BasicModelLoad.html" class="link-button">查看示例 →</a>
|
|
451
|
+
</div>
|
|
452
|
+
</div>
|
|
453
|
+
</section>
|
|
454
|
+
|
|
455
|
+
<!-- 场景管理示例 -->
|
|
456
|
+
<section class="category-section">
|
|
457
|
+
<h2 class="category-title">🎬 场景管理</h2>
|
|
458
|
+
<div class="examples-grid">
|
|
459
|
+
<div class="example-card" data-name="场景页面管理器" data-desc="场景切换">
|
|
460
|
+
<h3><span class="icon">🎭</span>场景页面管理器</h3>
|
|
461
|
+
<div class="description">演示如何使用场景页面管理器在不同预设场景之间切换。每个场景包含不同的相机位置、图层可见性等配置,支持平滑过渡动画。</div>
|
|
462
|
+
<div class="tags">
|
|
463
|
+
<span class="tag tag-demo">场景管理</span>
|
|
464
|
+
<span class="tag tag-feature">场景切换</span>
|
|
465
|
+
<span class="tag tag-feature">相机预设</span>
|
|
466
|
+
</div>
|
|
467
|
+
<a href="ScenePageDemo.html" class="link-button">查看示例 →</a>
|
|
468
|
+
</div>
|
|
469
|
+
|
|
470
|
+
<div class="example-card" data-name="场景页面管理器 Vue" data-desc="Vue版本">
|
|
471
|
+
<h3><span class="icon">⚡</span>场景页面管理器 (Vue)</h3>
|
|
472
|
+
<div class="description">场景页面管理器的Vue版本实现。展示了如何将Bc-model-viewer集成到Vue应用中,提供响应式的场景管理界面。</div>
|
|
473
|
+
<div class="tags">
|
|
474
|
+
<span class="tag tag-demo">Vue集成</span>
|
|
475
|
+
<span class="tag tag-feature">响应式</span>
|
|
476
|
+
</div>
|
|
477
|
+
<a href="ScenePageDemoVue.html" class="link-button">查看示例 →</a>
|
|
478
|
+
</div>
|
|
479
|
+
</div>
|
|
480
|
+
</section>
|
|
481
|
+
|
|
482
|
+
<footer class="footer">
|
|
483
|
+
<p>Bc-model-viewer 示例集合</p>
|
|
484
|
+
<p>点击上方卡片查看对应的示例演示</p>
|
|
485
|
+
</footer>
|
|
35
486
|
</div>
|
|
36
487
|
|
|
37
|
-
<script
|
|
488
|
+
<script>
|
|
489
|
+
/**
|
|
490
|
+
* 示例导航页面控制器
|
|
491
|
+
*/
|
|
492
|
+
class ExamplesIndexController {
|
|
493
|
+
constructor() {
|
|
494
|
+
this.searchInput = document.getElementById('searchInput');
|
|
495
|
+
this.exampleCards = Array.from(document.querySelectorAll('.example-card'));
|
|
496
|
+
this.searchDebounceTimer = null;
|
|
497
|
+
this.init();
|
|
498
|
+
}
|
|
38
499
|
|
|
39
|
-
|
|
500
|
+
/**
|
|
501
|
+
* 初始化
|
|
502
|
+
*/
|
|
503
|
+
init() {
|
|
504
|
+
this.setupSearch();
|
|
505
|
+
this.setupCardClick();
|
|
506
|
+
this.setupKeyboardShortcuts();
|
|
507
|
+
this.restoreSearchFromUrl();
|
|
508
|
+
}
|
|
40
509
|
|
|
510
|
+
/**
|
|
511
|
+
* 设置搜索功能(带防抖)
|
|
512
|
+
*/
|
|
513
|
+
setupSearch() {
|
|
514
|
+
this.searchInput.addEventListener('input', (e) => {
|
|
515
|
+
clearTimeout(this.searchDebounceTimer);
|
|
516
|
+
this.searchDebounceTimer = setTimeout(() => {
|
|
517
|
+
this.performSearch(e.target.value);
|
|
518
|
+
}, 150); // 150ms 防抖
|
|
519
|
+
});
|
|
41
520
|
|
|
42
|
-
|
|
521
|
+
// 清除搜索按钮
|
|
522
|
+
this.searchInput.addEventListener('keydown', (e) => {
|
|
523
|
+
if (e.key === 'Escape') {
|
|
524
|
+
this.searchInput.value = '';
|
|
525
|
+
this.performSearch('');
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* 执行搜索
|
|
532
|
+
* @param {string} searchTerm - 搜索关键词
|
|
533
|
+
*/
|
|
534
|
+
performSearch(searchTerm) {
|
|
535
|
+
const term = searchTerm.toLowerCase().trim();
|
|
536
|
+
let visibleCount = 0;
|
|
537
|
+
|
|
538
|
+
this.exampleCards.forEach(card => {
|
|
539
|
+
const isVisible = this.isCardMatch(card, term);
|
|
540
|
+
card.style.display = isVisible ? 'flex' : 'none';
|
|
541
|
+
if (isVisible) visibleCount++;
|
|
542
|
+
|
|
543
|
+
// 高亮匹配的文本
|
|
544
|
+
this.highlightMatch(card, term);
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
// 更新 URL(不刷新页面)
|
|
548
|
+
this.updateUrlSearchParam(term);
|
|
549
|
+
|
|
550
|
+
// 显示搜索结果统计
|
|
551
|
+
this.showSearchResult(term, visibleCount);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* 检查卡片是否匹配搜索条件
|
|
556
|
+
* @param {HTMLElement} card - 卡片元素
|
|
557
|
+
* @param {string} term - 搜索关键词
|
|
558
|
+
* @returns {boolean}
|
|
559
|
+
*/
|
|
560
|
+
isCardMatch(card, term) {
|
|
561
|
+
if (!term) return true;
|
|
562
|
+
|
|
563
|
+
const name = card.dataset.name?.toLowerCase() || '';
|
|
564
|
+
const desc = card.dataset.desc?.toLowerCase() || '';
|
|
565
|
+
const description = card.querySelector('.description')?.textContent.toLowerCase() || '';
|
|
566
|
+
const tags = Array.from(card.querySelectorAll('.tag'))
|
|
567
|
+
.map(tag => tag.textContent.toLowerCase())
|
|
568
|
+
.join(' ');
|
|
43
569
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
570
|
+
return name.includes(term) ||
|
|
571
|
+
desc.includes(term) ||
|
|
572
|
+
description.includes(term) ||
|
|
573
|
+
tags.includes(term);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* 高亮匹配的文本(优化版本,使用缓存)
|
|
578
|
+
* @param {HTMLElement} card - 卡片元素
|
|
579
|
+
* @param {string} term - 搜索关键词
|
|
580
|
+
*/
|
|
581
|
+
highlightMatch(card, term) {
|
|
582
|
+
const description = card.querySelector('.description');
|
|
583
|
+
if (!description) return;
|
|
584
|
+
|
|
585
|
+
// 如果没有原始文本缓存,先保存
|
|
586
|
+
if (!description.dataset.originalText) {
|
|
587
|
+
description.dataset.originalText = description.textContent;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (!term) {
|
|
591
|
+
// 恢复原始文本
|
|
592
|
+
description.textContent = description.dataset.originalText;
|
|
593
|
+
return;
|
|
49
594
|
}
|
|
595
|
+
|
|
596
|
+
// 高亮匹配文本
|
|
597
|
+
const originalText = description.dataset.originalText;
|
|
598
|
+
const escapedTerm = term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
599
|
+
const regex = new RegExp(`(${escapedTerm})`, 'gi');
|
|
600
|
+
const highlightedText = originalText.replace(
|
|
601
|
+
regex,
|
|
602
|
+
'<mark class="highlight">$1</mark>'
|
|
603
|
+
);
|
|
604
|
+
description.innerHTML = highlightedText;
|
|
50
605
|
}
|
|
51
|
-
})
|
|
52
606
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
607
|
+
/**
|
|
608
|
+
* 设置卡片点击事件(事件委托)
|
|
609
|
+
*/
|
|
610
|
+
setupCardClick() {
|
|
611
|
+
// 使用事件委托,提高性能
|
|
612
|
+
document.addEventListener('click', (e) => {
|
|
613
|
+
const card = e.target.closest('.example-card');
|
|
614
|
+
if (!card) return;
|
|
56
615
|
|
|
57
|
-
|
|
616
|
+
// 如果点击的是链接按钮,让浏览器处理默认行为
|
|
617
|
+
if (e.target.closest('.link-button')) {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
58
620
|
|
|
59
|
-
|
|
621
|
+
// 否则,触发链接跳转
|
|
622
|
+
const link = card.querySelector('.link-button');
|
|
623
|
+
if (link && link.href) {
|
|
624
|
+
e.preventDefault();
|
|
625
|
+
window.location.href = link.href;
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
}
|
|
60
629
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
630
|
+
/**
|
|
631
|
+
* 设置键盘快捷键
|
|
632
|
+
*/
|
|
633
|
+
setupKeyboardShortcuts() {
|
|
634
|
+
document.addEventListener('keydown', (e) => {
|
|
635
|
+
// Ctrl/Cmd + K 聚焦搜索框
|
|
636
|
+
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
|
637
|
+
e.preventDefault();
|
|
638
|
+
this.searchInput.focus();
|
|
639
|
+
this.searchInput.select();
|
|
640
|
+
}
|
|
64
641
|
|
|
642
|
+
// / 键聚焦搜索框
|
|
643
|
+
if (e.key === '/' && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA') {
|
|
644
|
+
e.preventDefault();
|
|
645
|
+
this.searchInput.focus();
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* 更新 URL 搜索参数
|
|
652
|
+
* @param {string} term - 搜索关键词
|
|
653
|
+
*/
|
|
654
|
+
updateUrlSearchParam(term) {
|
|
655
|
+
const url = new URL(window.location);
|
|
656
|
+
if (term) {
|
|
657
|
+
url.searchParams.set('q', term);
|
|
658
|
+
} else {
|
|
659
|
+
url.searchParams.delete('q');
|
|
660
|
+
}
|
|
661
|
+
window.history.replaceState({}, '', url);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* 从 URL 恢复搜索状态
|
|
666
|
+
*/
|
|
667
|
+
restoreSearchFromUrl() {
|
|
668
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
669
|
+
const query = urlParams.get('q');
|
|
670
|
+
if (query) {
|
|
671
|
+
this.searchInput.value = query;
|
|
672
|
+
this.performSearch(query);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* 显示搜索结果统计
|
|
678
|
+
* @param {string} term - 搜索关键词
|
|
679
|
+
* @param {number} visibleCount - 可见卡片数量
|
|
680
|
+
*/
|
|
681
|
+
showSearchResult(term, visibleCount) {
|
|
682
|
+
// 移除现有的结果提示
|
|
683
|
+
const existingResult = document.getElementById('search-result');
|
|
684
|
+
if (existingResult) {
|
|
685
|
+
existingResult.remove();
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (term && visibleCount === 0) {
|
|
689
|
+
// 显示无结果提示
|
|
690
|
+
const resultDiv = document.createElement('div');
|
|
691
|
+
resultDiv.id = 'search-result';
|
|
692
|
+
resultDiv.style.cssText = `
|
|
693
|
+
text-align: center;
|
|
694
|
+
color: white;
|
|
695
|
+
padding: 20px;
|
|
696
|
+
background: rgba(255, 255, 255, 0.1);
|
|
697
|
+
border-radius: 8px;
|
|
698
|
+
margin: 20px 0;
|
|
699
|
+
`;
|
|
700
|
+
resultDiv.textContent = `未找到匹配"${term}"的示例`;
|
|
701
|
+
this.searchInput.parentElement.insertAdjacentElement('afterend', resultDiv);
|
|
702
|
+
} else if (term) {
|
|
703
|
+
// 显示结果统计
|
|
704
|
+
const resultDiv = document.createElement('div');
|
|
705
|
+
resultDiv.id = 'search-result';
|
|
706
|
+
resultDiv.style.cssText = `
|
|
707
|
+
text-align: center;
|
|
708
|
+
color: white;
|
|
709
|
+
padding: 10px;
|
|
710
|
+
font-size: 0.9em;
|
|
711
|
+
opacity: 0.9;
|
|
712
|
+
`;
|
|
713
|
+
resultDiv.textContent = `找到 ${visibleCount} 个匹配的示例`;
|
|
714
|
+
this.searchInput.parentElement.insertAdjacentElement('afterend', resultDiv);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// 页面加载完成后初始化
|
|
720
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
721
|
+
new ExamplesIndexController();
|
|
722
|
+
});
|
|
723
|
+
</script>
|
|
65
724
|
</body>
|
|
66
725
|
|
|
67
|
-
</html>
|
|
726
|
+
</html>
|
|
727
|
+
|