@file-viewer/core 2.0.11 → 2.1.1

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.
Files changed (116) hide show
  1. package/README.en.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/config/options.d.ts +1 -1
  4. package/dist/config/options.js +1 -1
  5. package/dist/contracts/types.d.ts +76 -1
  6. package/dist/headless.d.ts +3 -3
  7. package/dist/headless.js +2 -2
  8. package/dist/index.d.ts +10 -7
  9. package/dist/index.js +106 -49
  10. package/dist/lifecycle/operations.d.ts +1 -0
  11. package/dist/lifecycle/operations.js +65 -6
  12. package/dist/platform/assets.d.ts +3 -1
  13. package/dist/platform/assets.js +43 -6
  14. package/dist/registry/capabilities.d.ts +2 -2
  15. package/dist/registry/capabilities.js +2 -1
  16. package/dist/registry/formats.d.ts +20 -7
  17. package/dist/registry/formats.js +14 -5
  18. package/dist/registry/registry.d.ts +8 -1
  19. package/dist/registry/registry.js +29 -0
  20. package/dist/renderers/image.js +1 -10
  21. package/dist/renderers/index.d.ts +320 -2
  22. package/dist/renderers/index.js +27 -157
  23. package/dist/viewer/createViewer.js +86 -3
  24. package/package.json +17 -44
  25. package/dist/renderers/archive.d.ts +0 -2
  26. package/dist/renderers/archive.js +0 -547
  27. package/dist/renderers/archiveCache.d.ts +0 -10
  28. package/dist/renderers/archiveCache.js +0 -96
  29. package/dist/renderers/archiveFallback.d.ts +0 -7
  30. package/dist/renderers/archiveFallback.js +0 -166
  31. package/dist/renderers/archiveShared.d.ts +0 -23
  32. package/dist/renderers/archiveShared.js +0 -71
  33. package/dist/renderers/audio.d.ts +0 -8
  34. package/dist/renderers/audio.js +0 -219
  35. package/dist/renderers/cad.d.ts +0 -2
  36. package/dist/renderers/cad.js +0 -446
  37. package/dist/renderers/code.d.ts +0 -11
  38. package/dist/renderers/code.js +0 -233
  39. package/dist/renderers/data.d.ts +0 -7
  40. package/dist/renderers/data.js +0 -370
  41. package/dist/renderers/drawing.d.ts +0 -10
  42. package/dist/renderers/drawing.js +0 -882
  43. package/dist/renderers/eda.d.ts +0 -2
  44. package/dist/renderers/eda.js +0 -434
  45. package/dist/renderers/edaParser.d.ts +0 -77
  46. package/dist/renderers/edaParser.js +0 -569
  47. package/dist/renderers/email.d.ts +0 -2
  48. package/dist/renderers/email.js +0 -463
  49. package/dist/renderers/epub.d.ts +0 -2
  50. package/dist/renderers/epub.js +0 -331
  51. package/dist/renderers/geo.d.ts +0 -2
  52. package/dist/renderers/geo.js +0 -284
  53. package/dist/renderers/markdown.d.ts +0 -2
  54. package/dist/renderers/markdown.js +0 -83
  55. package/dist/renderers/model.d.ts +0 -2
  56. package/dist/renderers/model.js +0 -567
  57. package/dist/renderers/ofd.d.ts +0 -2
  58. package/dist/renderers/ofd.js +0 -256
  59. package/dist/renderers/openDocument.d.ts +0 -2
  60. package/dist/renderers/openDocument.js +0 -122
  61. package/dist/renderers/pdf.d.ts +0 -3
  62. package/dist/renderers/pdf.js +0 -1001
  63. package/dist/renderers/pdfStyles.d.ts +0 -1
  64. package/dist/renderers/pdfStyles.js +0 -1
  65. package/dist/renderers/pptx.d.ts +0 -2
  66. package/dist/renderers/pptx.js +0 -217
  67. package/dist/renderers/spreadsheet/state.d.ts +0 -80
  68. package/dist/renderers/spreadsheet/state.js +0 -96
  69. package/dist/renderers/spreadsheet/view.d.ts +0 -25
  70. package/dist/renderers/spreadsheet/view.js +0 -833
  71. package/dist/renderers/spreadsheet/worker/index.d.ts +0 -2
  72. package/dist/renderers/spreadsheet/worker/index.js +0 -1
  73. package/dist/renderers/spreadsheet/worker/sheetjs/SheetJsModel.d.ts +0 -73
  74. package/dist/renderers/spreadsheet/worker/sheetjs/SheetJsModel.js +0 -623
  75. package/dist/renderers/spreadsheet/worker/sheetjs/color.d.ts +0 -2
  76. package/dist/renderers/spreadsheet/worker/sheetjs/color.js +0 -73
  77. package/dist/renderers/spreadsheet/worker/sheetjs/index.d.ts +0 -1
  78. package/dist/renderers/spreadsheet/worker/sheetjs/index.js +0 -1
  79. package/dist/renderers/spreadsheet/worker/sheetjs/parser.d.ts +0 -18
  80. package/dist/renderers/spreadsheet/worker/sheetjs/parser.js +0 -106
  81. package/dist/renderers/spreadsheet/worker/sheetjs/sheet.worker.d.ts +0 -1
  82. package/dist/renderers/spreadsheet/worker/sheetjs/sheet.worker.js +0 -11
  83. package/dist/renderers/spreadsheet/worker/type.d.ts +0 -57
  84. package/dist/renderers/spreadsheet/worker/type.js +0 -1
  85. package/dist/renderers/spreadsheet.d.ts +0 -3
  86. package/dist/renderers/spreadsheet.js +0 -929
  87. package/dist/renderers/typst.d.ts +0 -8
  88. package/dist/renderers/typst.js +0 -547
  89. package/dist/renderers/umd/parser.d.ts +0 -30
  90. package/dist/renderers/umd/parser.js +0 -408
  91. package/dist/renderers/umd.d.ts +0 -2
  92. package/dist/renderers/umd.js +0 -297
  93. package/dist/renderers/video.d.ts +0 -8
  94. package/dist/renderers/video.js +0 -108
  95. package/dist/renderers/wordDoc.d.ts +0 -5
  96. package/dist/renderers/wordDoc.js +0 -284
  97. package/dist/renderers/wordDocx.d.ts +0 -5
  98. package/dist/renderers/wordDocx.js +0 -985
  99. package/dist/renderers/wordDocx.worker.d.ts +0 -1
  100. package/dist/renderers/wordDocx.worker.js +0 -96
  101. package/vendor/ofd/dltech/jbig2/arithmetic_decoder.js +0 -183
  102. package/vendor/ofd/dltech/jbig2/ccitt.js +0 -1070
  103. package/vendor/ofd/dltech/jbig2/compatibility.js +0 -12
  104. package/vendor/ofd/dltech/jbig2/core_utils.js +0 -180
  105. package/vendor/ofd/dltech/jbig2/is_node.js +0 -27
  106. package/vendor/ofd/dltech/jbig2/jbig2.js +0 -2589
  107. package/vendor/ofd/dltech/jbig2/jbig2_stream.js +0 -81
  108. package/vendor/ofd/dltech/jbig2/primitives.js +0 -387
  109. package/vendor/ofd/dltech/jbig2/stream.js +0 -1348
  110. package/vendor/ofd/dltech/jbig2/util.js +0 -972
  111. package/vendor/ofd/dltech/ofd/ofd.d.ts +0 -11
  112. package/vendor/ofd/dltech/ofd/ofd.js +0 -100
  113. package/vendor/ofd/dltech/ofd/ofd_parser.js +0 -395
  114. package/vendor/ofd/dltech/ofd/ofd_render.js +0 -473
  115. package/vendor/ofd/dltech/ofd/ofd_util.js +0 -350
  116. package/vendor/ofd/dltech/ofd/pipeline.js +0 -26
@@ -1,83 +0,0 @@
1
- import { marked } from 'marked';
2
- import { createFileViewerZoomChangeEmitter as createZoomChangeEmitter } from '../features/document/zoom.js';
3
- import { registerFileViewerZoomProvider, unregisterFileViewerZoomProvider, } from '../features/document/dom/index.js';
4
- import { readFileViewerText as readText } from '../source/index.js';
5
- const markdownStyle = `
6
- .markdown-viewer{min-height:100%;padding:28px 16px 48px;background:#eef1f4;overflow:auto;box-sizing:border-box}
7
- .markdown-body{color-scheme:light;--bgColor-default:#fff;--bgColor-muted:#f6f8fa;--bgColor-neutral-muted:#818b981f;--borderColor-default:#d1d9e0;--borderColor-muted:#d1d9e0b3;--borderColor-neutral-muted:#d1d9e0b3;--fgColor-default:#1f2328;--fgColor-muted:#59636e;--fgColor-accent:#0969da;background:var(--bgColor-default);border:1px solid rgba(20,35,53,.1);border-radius:12px;margin:0 auto;box-sizing:border-box;min-width:200px;max-width:var(--markdown-max-width,980px);padding:var(--markdown-padding,45px);color:var(--fgColor-default);font-size:var(--markdown-font-size,16px);box-shadow:0 18px 42px rgba(15,23,42,.1)}
8
- .markdown-body h1,.markdown-body h2,.markdown-body h3{margin-top:24px;margin-bottom:16px;font-weight:700;line-height:1.25}
9
- .markdown-body h1{padding-bottom:.3em;border-bottom:1px solid var(--borderColor-muted);font-size:2em}
10
- .markdown-body h2{padding-bottom:.3em;border-bottom:1px solid var(--borderColor-muted);font-size:1.5em}
11
- .markdown-body p,.markdown-body ul,.markdown-body ol,.markdown-body blockquote,.markdown-body table,.markdown-body pre{margin-top:0;margin-bottom:16px}
12
- .markdown-body a{color:var(--fgColor-accent);text-decoration:none}
13
- .markdown-body a:hover{text-decoration:underline}
14
- .markdown-body code{padding:.2em .4em;border-radius:6px;background:var(--bgColor-neutral-muted);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono',monospace;font-size:85%}
15
- .markdown-body pre{padding:16px;overflow:auto;border-radius:8px;background:var(--bgColor-muted)}
16
- .markdown-body pre code{padding:0;background:transparent;font-size:100%}
17
- .markdown-body table{display:block;width:max-content;max-width:100%;overflow:auto;border-spacing:0;border-collapse:collapse}
18
- .markdown-body th,.markdown-body td{padding:6px 13px;border:1px solid var(--borderColor-default)}
19
- .markdown-body tr{background:var(--bgColor-default);border-top:1px solid var(--borderColor-muted)}
20
- .markdown-body tr:nth-child(2n){background:var(--bgColor-muted)}
21
- .markdown-body blockquote{padding:0 1em;color:var(--fgColor-muted);border-left:.25em solid var(--borderColor-default)}
22
- .file-viewer[data-viewer-theme='dark'] .markdown-viewer{background:#101820}
23
- .file-viewer[data-viewer-theme='dark'] .markdown-body{color-scheme:dark;--bgColor-default:#0d1117;--bgColor-muted:#151b23;--bgColor-neutral-muted:#656c7633;--borderColor-default:#3d444d;--borderColor-muted:#3d444db3;--borderColor-neutral-muted:#3d444db3;--fgColor-default:#f0f6fc;--fgColor-muted:#9198a1;--fgColor-accent:#4493f8;background:var(--bgColor-default);border-color:rgba(139,148,158,.26);color:var(--fgColor-default);box-shadow:0 24px 56px rgba(0,0,0,.38)}
24
- @media (max-width:767px){.markdown-viewer{padding:14px 10px 28px}.markdown-body{padding:22px 18px;border-radius:10px}}
25
- @media (prefers-color-scheme:dark){.file-viewer[data-viewer-theme='system'] .markdown-viewer{background:#101820}.file-viewer[data-viewer-theme='system'] .markdown-body{color-scheme:dark;--bgColor-default:#0d1117;--bgColor-muted:#151b23;--bgColor-neutral-muted:#656c7633;--borderColor-default:#3d444d;--borderColor-muted:#3d444db3;--borderColor-neutral-muted:#3d444db3;--fgColor-default:#f0f6fc;--fgColor-muted:#9198a1;--fgColor-accent:#4493f8;background:var(--bgColor-default);border-color:rgba(139,148,158,.26);color:var(--fgColor-default);box-shadow:0 24px 56px rgba(0,0,0,.38)}}
26
- `;
27
- const createStyle = () => {
28
- const style = document.createElement('style');
29
- style.textContent = markdownStyle;
30
- return style;
31
- };
32
- const clampZoom = (value) => {
33
- return Math.min(2.4, Math.max(0.6, Number(value.toFixed(2))));
34
- };
35
- const applyMarkdownZoom = (host, zoom) => {
36
- host.style.setProperty('--markdown-max-width', `${980 * zoom}px`);
37
- host.style.setProperty('--markdown-padding', `${45 * zoom}px`);
38
- host.style.setProperty('--markdown-font-size', `${16 * zoom}px`);
39
- };
40
- export default async function renderMarkdown(buffer, target) {
41
- const text = await readText(buffer);
42
- let zoom = 1;
43
- const zoomEmitter = createZoomChangeEmitter();
44
- const root = document.createElement('div');
45
- root.className = 'markdown-viewer';
46
- root.dataset.viewerZoomProvider = 'markdown';
47
- const article = document.createElement('article');
48
- article.className = 'markdown-body';
49
- article.innerHTML = await marked(text);
50
- applyMarkdownZoom(root, zoom);
51
- root.append(article);
52
- target.replaceChildren(createStyle(), root);
53
- const getZoomState = () => ({
54
- scale: zoom,
55
- label: `${Math.round(zoom * 100)}%`,
56
- canZoomIn: zoom < 2.4,
57
- canZoomOut: zoom > 0.6,
58
- canReset: zoom !== 1,
59
- minScale: 0.6,
60
- maxScale: 2.4,
61
- });
62
- const setZoom = (scale) => {
63
- zoom = clampZoom(scale);
64
- applyMarkdownZoom(root, zoom);
65
- zoomEmitter.emit();
66
- return getZoomState();
67
- };
68
- registerFileViewerZoomProvider(root, {
69
- zoomIn: () => setZoom(zoom + 0.1),
70
- zoomOut: () => setZoom(zoom - 0.1),
71
- resetZoom: () => setZoom(1),
72
- setZoom,
73
- getState: getZoomState,
74
- subscribe: zoomEmitter.subscribe,
75
- });
76
- return {
77
- $el: target,
78
- unmount() {
79
- unregisterFileViewerZoomProvider(root);
80
- target.replaceChildren();
81
- },
82
- };
83
- }
@@ -1,2 +0,0 @@
1
- import type { FileRenderContext, FileViewerRenderedInstance } from '../contracts/types';
2
- export default function renderModel(buffer: ArrayBuffer, target: HTMLDivElement, type?: string, context?: FileRenderContext): Promise<FileViewerRenderedInstance>;
@@ -1,567 +0,0 @@
1
- import * as THREE from 'three';
2
- import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
3
- const modelStyle = `
4
- .model-viewer{display:flex;height:100%;min-height:100%;flex-direction:column;background:#f8fafc;color:#162333}
5
- .model-viewer *{box-sizing:border-box}
6
- .model-toolbar{display:flex;min-height:48px;align-items:center;justify-content:space-between;gap:16px;padding:0 12px;border-bottom:1px solid rgba(15,23,42,.08);background:#fff}
7
- .model-actions{display:flex;min-width:0;flex-wrap:wrap;gap:6px}
8
- .model-actions button{min-height:30px;border:0;border-radius:8px;padding:0 10px;background:rgba(15,23,42,.06);color:#475569;cursor:pointer;font-size:12px;font-weight:700;letter-spacing:0;transition:background-color .18s ease,color .18s ease}
9
- .model-actions button.active,.model-actions button:hover{background:rgba(33,163,102,.14);color:#16804f}
10
- .model-meta{min-width:0;display:flex;align-items:center;justify-content:flex-end;gap:8px;color:#64748b;font-size:12px}
11
- .model-meta strong{color:#0f766e;font-weight:800}
12
- .model-meta span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
13
- .model-stage{position:relative;flex:1;min-height:0;overflow:hidden}
14
- .model-stage canvas{display:block;width:100%;height:100%;outline:none}
15
- .model-state{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:24px;background:rgba(248,250,252,.88);color:#64748b;text-align:center;line-height:1.7}
16
- .model-state[hidden]{display:none!important}
17
- .model-state.error{color:#b42318}
18
- .model-state strong{color:#b42318;font-size:18px}
19
- @media (max-width:720px){.model-toolbar{min-height:64px;align-items:flex-start;flex-direction:column;gap:8px;padding:8px 10px}.model-meta{width:100%;justify-content:flex-start}}
20
- `;
21
- class ModelPreviewNotice extends Error {
22
- }
23
- const createStyle = () => {
24
- const style = document.createElement('style');
25
- style.textContent = modelStyle;
26
- return style;
27
- };
28
- const createElement = (tagName, className, text) => {
29
- const element = document.createElement(tagName);
30
- if (className) {
31
- element.className = className;
32
- }
33
- if (text !== undefined) {
34
- element.textContent = text;
35
- }
36
- return element;
37
- };
38
- const normalizeError = (reason) => {
39
- if (reason instanceof Error) {
40
- return reason.message;
41
- }
42
- if (typeof reason === 'string') {
43
- return reason;
44
- }
45
- try {
46
- return JSON.stringify(reason);
47
- }
48
- catch {
49
- return String(reason);
50
- }
51
- };
52
- const getResourcePath = (sourceUrl) => {
53
- if (!sourceUrl) {
54
- return '';
55
- }
56
- try {
57
- return new URL('.', sourceUrl).href;
58
- }
59
- catch {
60
- const clean = sourceUrl.split(/[?#]/)[0] || sourceUrl;
61
- const slashIndex = clean.lastIndexOf('/');
62
- return slashIndex >= 0 ? clean.slice(0, slashIndex + 1) : '';
63
- }
64
- };
65
- const disposeMaterial = (material) => {
66
- const materials = Array.isArray(material) ? material : [material];
67
- materials.forEach(item => item.dispose());
68
- };
69
- const disposeObject = (object) => {
70
- object.traverse(child => {
71
- const mesh = child;
72
- const points = child;
73
- if (mesh.geometry) {
74
- mesh.geometry.dispose();
75
- }
76
- if (mesh.material) {
77
- disposeMaterial(mesh.material);
78
- }
79
- if (points.material) {
80
- disposeMaterial(points.material);
81
- }
82
- });
83
- };
84
- export default async function renderModel(buffer, target, type = 'glb', context) {
85
- const normalizedType = type.toLowerCase();
86
- const sourceUrl = context === null || context === void 0 ? void 0 : context.url;
87
- let status = 'loading';
88
- let errorMessage = '';
89
- let objectSummary = '正在加载模型';
90
- let autoRotate = false;
91
- let wireframe = false;
92
- let showGrid = true;
93
- let showAxes = true;
94
- let renderer = null;
95
- let scene = null;
96
- let camera = null;
97
- let controls = null;
98
- let modelRoot = null;
99
- let gridHelper = null;
100
- let axesHelper = null;
101
- let resizeObserver = null;
102
- let animationFrame = 0;
103
- let activeVersion = 0;
104
- let mixer = null;
105
- const clock = new THREE.Clock();
106
- const root = createElement('div', 'model-viewer');
107
- const toolbar = createElement('div', 'model-toolbar');
108
- const actions = createElement('div', 'model-actions');
109
- const fitButton = createElement('button', undefined, '适配');
110
- const rotateButton = createElement('button', undefined, '旋转');
111
- const wireframeButton = createElement('button', undefined, '线框');
112
- const gridButton = createElement('button', undefined, '网格');
113
- const axesButton = createElement('button', undefined, '坐标');
114
- const meta = createElement('div', 'model-meta');
115
- const typeText = createElement('strong', undefined, normalizedType.toUpperCase());
116
- const summaryText = createElement('span', undefined, objectSummary);
117
- const stage = createElement('div', 'model-stage');
118
- const canvas = document.createElement('canvas');
119
- const state = createElement('div', 'model-state', '正在解析 3D 模型...');
120
- const buttons = [fitButton, rotateButton, wireframeButton, gridButton, axesButton];
121
- buttons.forEach(button => {
122
- button.type = 'button';
123
- });
124
- actions.append(fitButton, rotateButton, wireframeButton, gridButton, axesButton);
125
- meta.append(typeText, summaryText);
126
- toolbar.append(actions, meta);
127
- stage.append(canvas, state);
128
- root.append(toolbar, stage);
129
- target.replaceChildren(createStyle(), root);
130
- const readText = () => {
131
- if (typeof TextDecoder === 'function') {
132
- return new TextDecoder('utf-8').decode(buffer);
133
- }
134
- const bytes = new Uint8Array(buffer);
135
- let text = '';
136
- for (let index = 0; index < bytes.length; index += 1) {
137
- text += String.fromCharCode(bytes[index]);
138
- }
139
- return text;
140
- };
141
- const updateUi = () => {
142
- rotateButton.classList.toggle('active', autoRotate);
143
- wireframeButton.classList.toggle('active', wireframe);
144
- gridButton.classList.toggle('active', showGrid);
145
- axesButton.classList.toggle('active', showAxes);
146
- summaryText.textContent = objectSummary;
147
- state.hidden = status === 'ready';
148
- state.classList.toggle('error', status === 'error');
149
- if (status === 'loading') {
150
- state.textContent = '正在解析 3D 模型...';
151
- }
152
- else if (status === 'error') {
153
- state.replaceChildren(createElement('strong', undefined, '模型解析失败'), createElement('span', undefined, errorMessage));
154
- }
155
- };
156
- const updateHelperVisibility = () => {
157
- if (gridHelper) {
158
- gridHelper.visible = showGrid;
159
- }
160
- if (axesHelper) {
161
- axesHelper.visible = showAxes;
162
- }
163
- updateUi();
164
- };
165
- const resize = () => {
166
- if (!renderer || !camera) {
167
- return;
168
- }
169
- const rect = canvas.getBoundingClientRect();
170
- const width = Math.max(1, Math.floor(rect.width));
171
- const height = Math.max(1, Math.floor(rect.height));
172
- renderer.setSize(width, height, false);
173
- camera.aspect = width / height;
174
- camera.updateProjectionMatrix();
175
- };
176
- const ensureScene = () => {
177
- if (!renderer) {
178
- renderer = new THREE.WebGLRenderer({
179
- antialias: true,
180
- alpha: false,
181
- canvas,
182
- powerPreference: 'high-performance',
183
- });
184
- renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
185
- renderer.outputColorSpace = THREE.SRGBColorSpace;
186
- renderer.setClearColor(0xf8fafc, 1);
187
- }
188
- if (!scene) {
189
- scene = new THREE.Scene();
190
- scene.background = new THREE.Color(0xf8fafc);
191
- const hemiLight = new THREE.HemisphereLight(0xffffff, 0xd7dee8, 2.4);
192
- scene.add(hemiLight);
193
- const keyLight = new THREE.DirectionalLight(0xffffff, 2.2);
194
- keyLight.position.set(8, 10, 8);
195
- scene.add(keyLight);
196
- const fillLight = new THREE.DirectionalLight(0xffffff, 0.9);
197
- fillLight.position.set(-7, 5, -4);
198
- scene.add(fillLight);
199
- gridHelper = new THREE.GridHelper(10, 10, 0xcbd5e1, 0xe2e8f0);
200
- scene.add(gridHelper);
201
- axesHelper = new THREE.AxesHelper(3);
202
- scene.add(axesHelper);
203
- }
204
- if (!camera) {
205
- camera = new THREE.PerspectiveCamera(45, 1, 0.01, 100000);
206
- camera.position.set(5, 4, 6);
207
- }
208
- if (!controls && camera && renderer) {
209
- controls = new OrbitControls(camera, renderer.domElement);
210
- controls.enableDamping = true;
211
- controls.dampingFactor = 0.08;
212
- controls.screenSpacePanning = true;
213
- controls.autoRotateSpeed = 1.2;
214
- }
215
- updateHelperVisibility();
216
- resize();
217
- };
218
- const clearModel = () => {
219
- if (modelRoot && scene) {
220
- scene.remove(modelRoot);
221
- disposeObject(modelRoot);
222
- }
223
- modelRoot = null;
224
- mixer = null;
225
- };
226
- const createSurfaceMaterial = () => new THREE.MeshStandardMaterial({
227
- color: 0x4f8fba,
228
- metalness: 0.08,
229
- roughness: 0.78,
230
- side: THREE.DoubleSide,
231
- wireframe,
232
- });
233
- const createPointMaterial = () => new THREE.PointsMaterial({
234
- color: 0x1f7a8c,
235
- size: 0.035,
236
- sizeAttenuation: true,
237
- });
238
- const applyDefaultMaterials = (object) => {
239
- object.traverse(child => {
240
- const mesh = child;
241
- if (mesh.isMesh && !mesh.material) {
242
- mesh.material = createSurfaceMaterial();
243
- }
244
- if (mesh.isMesh && mesh.material) {
245
- const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
246
- materials.forEach(material => {
247
- if ('wireframe' in material) {
248
- material.wireframe = wireframe;
249
- }
250
- material.needsUpdate = true;
251
- });
252
- }
253
- });
254
- };
255
- const countMeshes = (object) => {
256
- let meshes = 0;
257
- let points = 0;
258
- object.traverse(child => {
259
- if (child.isMesh) {
260
- meshes += 1;
261
- }
262
- if (child.isPoints) {
263
- points += 1;
264
- }
265
- });
266
- return { meshes, points };
267
- };
268
- const summarizeModel = (object) => {
269
- const { meshes, points } = countMeshes(object);
270
- const parts = [];
271
- if (meshes) {
272
- parts.push(`${meshes} 个网格`);
273
- }
274
- if (points) {
275
- parts.push(`${points} 个点云`);
276
- }
277
- objectSummary = parts.length ? parts.join(',') : '模型已加载';
278
- updateUi();
279
- };
280
- const normalizeObject = (object) => {
281
- const box = new THREE.Box3().setFromObject(object);
282
- if (box.isEmpty()) {
283
- return {
284
- center: new THREE.Vector3(),
285
- size: new THREE.Vector3(4, 4, 4),
286
- };
287
- }
288
- const center = box.getCenter(new THREE.Vector3());
289
- const size = box.getSize(new THREE.Vector3());
290
- object.position.sub(center);
291
- return {
292
- center: new THREE.Vector3(),
293
- size,
294
- };
295
- };
296
- const fitToView = () => {
297
- if (!modelRoot || !camera || !controls) {
298
- return;
299
- }
300
- const box = new THREE.Box3().setFromObject(modelRoot);
301
- const size = box.getSize(new THREE.Vector3());
302
- const center = box.getCenter(new THREE.Vector3());
303
- const radius = Math.max(size.x, size.y, size.z, 1);
304
- const distance = radius / (2 * Math.tan(THREE.MathUtils.degToRad(camera.fov / 2))) * 1.65;
305
- camera.near = Math.max(distance / 1000, 0.01);
306
- camera.far = Math.max(distance * 1000, 1000);
307
- camera.position.copy(center).add(new THREE.Vector3(distance, distance * 0.62, distance));
308
- camera.updateProjectionMatrix();
309
- controls.target.copy(center);
310
- controls.update();
311
- };
312
- const addModelToScene = async (object) => {
313
- if (!scene) {
314
- return;
315
- }
316
- clearModel();
317
- applyDefaultMaterials(object);
318
- const { size } = normalizeObject(object);
319
- modelRoot = object;
320
- scene.add(object);
321
- fitToView();
322
- summarizeModel(object);
323
- const maxSize = Math.max(size.x, size.y, size.z, 1);
324
- if (gridHelper) {
325
- gridHelper.scale.setScalar(Math.max(maxSize / 10, 1));
326
- }
327
- };
328
- const parseGlbOrGltf = async () => {
329
- const { GLTFLoader } = await import('three/addons/loaders/GLTFLoader.js');
330
- const loader = new GLTFLoader();
331
- const resourcePath = getResourcePath(sourceUrl);
332
- const input = normalizedType === 'gltf' ? readText() : buffer;
333
- return await new Promise((resolve, reject) => {
334
- loader.parse(input, resourcePath, gltf => {
335
- var _a;
336
- if ((_a = gltf.animations) === null || _a === void 0 ? void 0 : _a.length) {
337
- mixer = new THREE.AnimationMixer(gltf.scene);
338
- gltf.animations.forEach(clip => mixer === null || mixer === void 0 ? void 0 : mixer.clipAction(clip).play());
339
- }
340
- resolve(gltf.scene);
341
- }, reject);
342
- });
343
- };
344
- const parseObj = async () => {
345
- const { OBJLoader } = await import('three/addons/loaders/OBJLoader.js');
346
- return new OBJLoader().parse(readText());
347
- };
348
- const parseStl = async () => {
349
- const { STLLoader } = await import('three/addons/loaders/STLLoader.js');
350
- const geometry = new STLLoader().parse(buffer);
351
- geometry.computeVertexNormals();
352
- return new THREE.Mesh(geometry, createSurfaceMaterial());
353
- };
354
- const parsePly = async () => {
355
- const { PLYLoader } = await import('three/addons/loaders/PLYLoader.js');
356
- const geometry = new PLYLoader().parse(buffer);
357
- geometry.computeVertexNormals();
358
- return new THREE.Mesh(geometry, createSurfaceMaterial());
359
- };
360
- const parseFbx = async () => {
361
- var _a;
362
- const { FBXLoader } = await import('three/addons/loaders/FBXLoader.js');
363
- const object = new FBXLoader().parse(buffer, getResourcePath(sourceUrl));
364
- if ((_a = object.animations) === null || _a === void 0 ? void 0 : _a.length) {
365
- mixer = new THREE.AnimationMixer(object);
366
- object.animations.forEach((clip) => mixer === null || mixer === void 0 ? void 0 : mixer.clipAction(clip).play());
367
- }
368
- return object;
369
- };
370
- const parseDae = async () => {
371
- const { ColladaLoader } = await import('three/addons/loaders/ColladaLoader.js');
372
- const result = new ColladaLoader().parse(readText(), getResourcePath(sourceUrl));
373
- if (!(result === null || result === void 0 ? void 0 : result.scene)) {
374
- throw new Error('DAE 模型未解析出有效场景');
375
- }
376
- return result.scene;
377
- };
378
- const parse3ds = async () => {
379
- const { TDSLoader } = await import('three/addons/loaders/TDSLoader.js');
380
- return new TDSLoader().parse(buffer, getResourcePath(sourceUrl));
381
- };
382
- const parse3mf = async () => {
383
- const { ThreeMFLoader } = await import('three/addons/loaders/3MFLoader.js');
384
- return new ThreeMFLoader().parse(buffer);
385
- };
386
- const parseAmf = async () => {
387
- const { AMFLoader } = await import('three/addons/loaders/AMFLoader.js');
388
- return new AMFLoader().parse(buffer);
389
- };
390
- const parseUsd = async () => {
391
- const { USDLoader } = await import('three/addons/loaders/USDLoader.js');
392
- return new USDLoader().parse(buffer);
393
- };
394
- const parseKmz = async () => {
395
- const { KMZLoader } = await import('three/addons/loaders/KMZLoader.js');
396
- return new KMZLoader().parse(buffer).scene;
397
- };
398
- const explainEngineeringModel = (modelType) => {
399
- const upperType = modelType.toUpperCase();
400
- if (modelType === 'ifc') {
401
- throw new ModelPreviewNotice('IFC 是 BIM 模型格式,浏览器端完整解析通常依赖 web-ifc 这类 WebAssembly BIM 内核。当前 Apache-2.0 前端包不默认打入这类重型运行时,建议在私有服务端转换为 GLB/GLTF 后预览。');
402
- }
403
- if (modelType === '3dm') {
404
- throw new ModelPreviewNotice('3DM 是 Rhino/OpenNURBS 模型格式,浏览器端解析需要 rhino3dm WebAssembly 运行时。当前前端包未内置该运行时,建议在私有转换链路输出 GLB/GLTF 后预览。');
405
- }
406
- throw new ModelPreviewNotice(`${upperType} 属于 CAD B-Rep / 工程交换格式,浏览器端完整解析通常需要 OpenCascade 等 WebAssembly 几何内核。当前前端包不默认打入这类重型运行时,建议在私有服务端转换为 GLB/GLTF 或轻量网格格式后预览。`);
407
- };
408
- const parsePcd = async () => {
409
- const { PCDLoader } = await import('three/addons/loaders/PCDLoader.js');
410
- return new PCDLoader().parse(buffer, sourceUrl || 'model.pcd');
411
- };
412
- const parseVrml = async () => {
413
- const { VRMLLoader } = await import('three/addons/loaders/VRMLLoader.js');
414
- return new VRMLLoader().parse(readText(), getResourcePath(sourceUrl));
415
- };
416
- const parseXyz = async () => {
417
- const { XYZLoader } = await import('three/addons/loaders/XYZLoader.js');
418
- const geometry = new XYZLoader().parse(readText());
419
- geometry.computeBoundingSphere();
420
- return new THREE.Points(geometry, createPointMaterial());
421
- };
422
- const parseVtk = async () => {
423
- const { VTKLoader } = await import('three/addons/loaders/VTKLoader.js');
424
- const geometry = new VTKLoader().parse(buffer);
425
- geometry.computeVertexNormals();
426
- return new THREE.Mesh(geometry, createSurfaceMaterial());
427
- };
428
- const parseModel = (modelType) => {
429
- switch (modelType) {
430
- case 'glb':
431
- case 'gltf':
432
- return parseGlbOrGltf();
433
- case 'obj':
434
- return parseObj();
435
- case 'stl':
436
- return parseStl();
437
- case 'ply':
438
- return parsePly();
439
- case 'fbx':
440
- return parseFbx();
441
- case 'dae':
442
- return parseDae();
443
- case '3ds':
444
- return parse3ds();
445
- case '3mf':
446
- return parse3mf();
447
- case 'amf':
448
- return parseAmf();
449
- case 'usd':
450
- case 'usda':
451
- case 'usdc':
452
- case 'usdz':
453
- return parseUsd();
454
- case 'kmz':
455
- return parseKmz();
456
- case 'step':
457
- case 'stp':
458
- case 'iges':
459
- case 'igs':
460
- case 'ifc':
461
- case '3dm':
462
- return explainEngineeringModel(modelType);
463
- case 'pcd':
464
- return parsePcd();
465
- case 'wrl':
466
- case 'vrml':
467
- return parseVrml();
468
- case 'xyz':
469
- return parseXyz();
470
- case 'vtk':
471
- case 'vtp':
472
- return parseVtk();
473
- default:
474
- throw new Error(`暂不支持 .${modelType} 模型格式`);
475
- }
476
- };
477
- const loadModel = async () => {
478
- const version = ++activeVersion;
479
- status = 'loading';
480
- errorMessage = '';
481
- objectSummary = '正在加载模型';
482
- updateUi();
483
- ensureScene();
484
- try {
485
- const object = await parseModel(normalizedType);
486
- if (version !== activeVersion) {
487
- disposeObject(object);
488
- return;
489
- }
490
- await addModelToScene(object);
491
- status = 'ready';
492
- updateUi();
493
- }
494
- catch (reason) {
495
- if (version !== activeVersion) {
496
- return;
497
- }
498
- if (!(reason instanceof ModelPreviewNotice)) {
499
- console.error(reason);
500
- }
501
- status = 'error';
502
- errorMessage = normalizeError(reason) || `${normalizedType.toUpperCase()} 模型解析失败`;
503
- updateUi();
504
- }
505
- };
506
- const renderFrame = () => {
507
- if (!renderer || !scene || !camera || !controls) {
508
- return;
509
- }
510
- controls.autoRotate = autoRotate;
511
- controls.update();
512
- const delta = clock.getDelta();
513
- mixer === null || mixer === void 0 ? void 0 : mixer.update(delta);
514
- renderer.render(scene, camera);
515
- animationFrame = window.requestAnimationFrame(renderFrame);
516
- };
517
- const updateWireframe = () => {
518
- if (modelRoot) {
519
- applyDefaultMaterials(modelRoot);
520
- }
521
- updateUi();
522
- };
523
- fitButton.addEventListener('click', fitToView);
524
- rotateButton.addEventListener('click', () => {
525
- autoRotate = !autoRotate;
526
- updateUi();
527
- });
528
- wireframeButton.addEventListener('click', () => {
529
- wireframe = !wireframe;
530
- updateWireframe();
531
- });
532
- gridButton.addEventListener('click', () => {
533
- showGrid = !showGrid;
534
- updateHelperVisibility();
535
- });
536
- axesButton.addEventListener('click', () => {
537
- showAxes = !showAxes;
538
- updateHelperVisibility();
539
- });
540
- updateUi();
541
- ensureScene();
542
- resizeObserver = new ResizeObserver(resize);
543
- resizeObserver.observe(canvas);
544
- clock.start();
545
- renderFrame();
546
- void loadModel();
547
- return {
548
- $el: root,
549
- unmount() {
550
- activeVersion += 1;
551
- window.cancelAnimationFrame(animationFrame);
552
- resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
553
- resizeObserver = null;
554
- clearModel();
555
- controls === null || controls === void 0 ? void 0 : controls.dispose();
556
- controls = null;
557
- renderer === null || renderer === void 0 ? void 0 : renderer.dispose();
558
- renderer = null;
559
- clock.stop();
560
- scene = null;
561
- camera = null;
562
- gridHelper = null;
563
- axesHelper = null;
564
- target.replaceChildren();
565
- },
566
- };
567
- }
@@ -1,2 +0,0 @@
1
- import type { FileRenderContext, FileViewerRenderedInstance } from '../contracts/types';
2
- export default function renderOfd(buffer: ArrayBuffer, target: HTMLDivElement, context?: FileRenderContext): Promise<FileViewerRenderedInstance>;