forked from kimminsung/dwg-dxf-viewer-sample
refactor: extract viewer2d workspace package
This commit is contained in:
1 parent
95fa6a452b
commit
5e10bb1be4
27 files changed
+1588
-704
No files matched your search
Generated
+1465
-675
File diff suppressed because it is too large.
Load diff
+13
-7
@@ -4,20 +4,26 @@
|
||||
"version": "0.1.0",
|
||||
"description": "Standalone sample: compose acadrust-dwg + dxf-parser + Viewer2D (sibling of hmwebviewer)",
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "vite --port 5173 --strictPort",
|
||||
"build": "tsc --noEmit && vite build",
|
||||
"preview": "vite preview",
|
||||
"typecheck": "tsc --noEmit"
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run",
|
||||
"test:unit": "vitest run tests/viewer2d.contract.test.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"dxf-parser": "^1.1.2",
|
||||
"opentype.js": "^2.0.0",
|
||||
"three": "^0.185.1"
|
||||
"@hmwebviewer/viewer2d": "workspace:*",
|
||||
"three": "0.185.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/three": "^0.185.1",
|
||||
"typescript": "^5.6.0",
|
||||
"vite": "^5.4.0"
|
||||
"@playwright/test": "1.62.0",
|
||||
"@types/three": "0.185.1",
|
||||
"typescript": "7.0.2",
|
||||
"vite": "8.1.5",
|
||||
"vitest": "4.1.10"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@hmwebviewer/viewer2d",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"types": "./src/index.ts",
|
||||
"dependencies": {
|
||||
"dxf-parser": "1.1.2",
|
||||
"opentype.js": "2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"three": "0.185.1"
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
Vendored
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,42 @@
|
||||
import { Viewer2D } from './Viewer2D.js';
|
||||
import { parseDwgBuffer, type CadParseResult } from './dwgParser';
|
||||
import { is2D, isDwg } from './ext2d';
|
||||
import { parseDxfBuffer } from './parseDxf';
|
||||
import { setDefaultFontUrl } from './slugText';
|
||||
|
||||
export type { CadParseResult } from './dwgParser';
|
||||
|
||||
export type CadInput = {
|
||||
name: string;
|
||||
data: ArrayBuffer | Uint8Array;
|
||||
};
|
||||
|
||||
export type Viewer2DOptions = {
|
||||
fontUrl?: string;
|
||||
};
|
||||
|
||||
function toArrayBuffer(data: ArrayBuffer | Uint8Array): ArrayBuffer {
|
||||
if (data instanceof ArrayBuffer) return data;
|
||||
return data.slice().buffer as ArrayBuffer;
|
||||
}
|
||||
|
||||
export function isCad2DFile(name: string): boolean {
|
||||
return is2D(name);
|
||||
}
|
||||
|
||||
export async function parseCad(input: CadInput): Promise<CadParseResult> {
|
||||
const buffer = toArrayBuffer(input.data);
|
||||
if (isDwg(input.name)) return parseDwgBuffer(new Uint8Array(buffer));
|
||||
if (is2D(input.name)) return parseDxfBuffer(buffer);
|
||||
|
||||
const head = new TextDecoder('latin1').decode(
|
||||
new Uint8Array(buffer, 0, Math.min(6, buffer.byteLength)),
|
||||
);
|
||||
if (head.startsWith('AC')) return parseDwgBuffer(new Uint8Array(buffer));
|
||||
return parseDxfBuffer(buffer);
|
||||
}
|
||||
|
||||
export function createViewer2D(container: HTMLElement, options: Viewer2DOptions = {}): Viewer2D {
|
||||
if (options.fontUrl) setDefaultFontUrl(options.fontUrl);
|
||||
return new Viewer2D(container);
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
+17
-21
@@ -20,11 +20,12 @@
|
||||
*/
|
||||
|
||||
// ── ① 모듈 지도의 각 카드 (src/viewer2d/*) ────────────────────────
|
||||
import { Viewer2D } from './viewer2d/Viewer2D.js';
|
||||
import { parseDwgBuffer, type CadParseResult } from './viewer2d/dwgParser';
|
||||
import { parseDxfBuffer } from './viewer2d/parseDxf';
|
||||
import { is2D, isDxf, isDwg } from './viewer2d/ext2d';
|
||||
import { setDefaultFontUrl } from './viewer2d/slugText';
|
||||
import {
|
||||
createViewer2D,
|
||||
isCad2DFile,
|
||||
parseCad,
|
||||
type CadParseResult,
|
||||
} from '@hmwebviewer/viewer2d';
|
||||
|
||||
// parseDxfBuffer 내부:
|
||||
// dxf-parser → HatchHandler → dxfAdapter
|
||||
@@ -32,7 +33,8 @@ import { setDefaultFontUrl } from './viewer2d/slugText';
|
||||
// acadrustParser → acadrust-dwg WASM
|
||||
|
||||
// ── ② 호스트 정적 자산 ──────────────────────────────────────────
|
||||
setDefaultFontUrl('/fonts/NanumGothic-Regular.ttf');
|
||||
const appBase = new URL(import.meta.env.BASE_URL, window.location.origin);
|
||||
const publicUrl = (path: string) => new URL(path, appBase).href;
|
||||
|
||||
// ── ③ Viewer2D 마운트 ───────────────────────────────────────────
|
||||
const app = document.getElementById('app')!;
|
||||
@@ -45,7 +47,9 @@ function setStatus(msg: string, err = false) {
|
||||
statusEl.classList.toggle('err', err);
|
||||
}
|
||||
|
||||
const viewer = new Viewer2D(app);
|
||||
const viewer = createViewer2D(app, {
|
||||
fontUrl: publicUrl('fonts/NanumGothic-Regular.ttf'),
|
||||
});
|
||||
viewer.onSelect((entity: unknown) => {
|
||||
if (!entity) {
|
||||
setStatus('deselected');
|
||||
@@ -56,18 +60,8 @@ viewer.onSelect((entity: unknown) => {
|
||||
});
|
||||
|
||||
// ── ④ 파서 조합 ─────────────────────────────────────────────────
|
||||
async function parseCad(buf: ArrayBuffer, name: string): Promise<CadParseResult> {
|
||||
if (isDxf(name)) return parseDxfBuffer(buf);
|
||||
if (isDwg(name)) return parseDwgBuffer(new Uint8Array(buf));
|
||||
const head = new TextDecoder('latin1').decode(
|
||||
new Uint8Array(buf, 0, Math.min(6, buf.byteLength)),
|
||||
);
|
||||
if (head.startsWith('AC')) return parseDwgBuffer(new Uint8Array(buf));
|
||||
return parseDxfBuffer(buf);
|
||||
}
|
||||
|
||||
async function loadAndRender(buf: ArrayBuffer, name: string): Promise<CadParseResult> {
|
||||
const result = await parseCad(buf, name);
|
||||
const result = await parseCad({ data: buf, name });
|
||||
viewer.load(result);
|
||||
viewer.resize();
|
||||
return result;
|
||||
@@ -81,7 +75,7 @@ async function loadUrl(url: string, nameHint?: string) {
|
||||
}
|
||||
|
||||
async function loadFile(file: File) {
|
||||
if (!is2D(file.name)) throw new Error(`not .dwg/.dxf: ${file.name}`);
|
||||
if (!isCad2DFile(file.name)) throw new Error(`not .dwg/.dxf: ${file.name}`);
|
||||
return loadAndRender(await file.arrayBuffer(), file.name);
|
||||
}
|
||||
|
||||
@@ -129,10 +123,12 @@ async function run(label: string, job: () => Promise<CadParseResult>) {
|
||||
}
|
||||
|
||||
document.getElementById('sample')!.addEventListener('click', () => {
|
||||
void run('BasicSample.dwg', () => loadUrl('/samples/BasicSample.dwg', 'BasicSample.dwg'));
|
||||
void run('BasicSample.dwg', () =>
|
||||
loadUrl(publicUrl('samples/BasicSample.dwg'), 'BasicSample.dwg'),
|
||||
);
|
||||
});
|
||||
document.getElementById('sampleDxf')!.addEventListener('click', () => {
|
||||
void run('simple.dxf', () => loadUrl('/samples/simple.dxf', 'simple.dxf'));
|
||||
void run('simple.dxf', () => loadUrl(publicUrl('samples/simple.dxf'), 'simple.dxf'));
|
||||
});
|
||||
document.getElementById('file')!.addEventListener('change', (ev) => {
|
||||
const file = (ev.target as HTMLInputElement).files?.[0];
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { isCad2DFile, parseCad } from '@hmwebviewer/viewer2d';
|
||||
|
||||
describe('viewer2d package interface', () => {
|
||||
it('parses the sample DXF through the public package interface', async () => {
|
||||
const file = await readFile(new URL('../public/samples/simple.dxf', import.meta.url));
|
||||
const result = await parseCad({
|
||||
name: 'simple.dxf',
|
||||
data: file.buffer.slice(file.byteOffset, file.byteOffset + file.byteLength),
|
||||
});
|
||||
const entities = result.entities as Array<{ layer?: string; type?: string }>;
|
||||
|
||||
expect(isCad2DFile('drawing.DWG')).toBe(true);
|
||||
expect(isCad2DFile('drawing.dxf')).toBe(true);
|
||||
expect(isCad2DFile('drawing.pdf')).toBe(false);
|
||||
expect(entities.map(({ type, layer }) => [type, layer])).toEqual([
|
||||
['LINE', 'OUTLINE'],
|
||||
['LINE', 'OUTLINE'],
|
||||
['LINE', 'OUTLINE'],
|
||||
['LINE', 'OUTLINE'],
|
||||
['CIRCLE', '0'],
|
||||
['TEXT', '0'],
|
||||
]);
|
||||
});
|
||||
});
|
||||
+1
-1
@@ -11,5 +11,5 @@
|
||||
"isolatedModules": true,
|
||||
"allowJs": true
|
||||
},
|
||||
"include": ["src/**/*", "vite.config.ts"]
|
||||
"include": ["src/**/*", "packages/*/src/**/*", "vite.config.ts"]
|
||||
}
|
||||
Reference in new issue
Block a user