@file-viewer/renderer-cad 3.0.0 → 3.0.2
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/README.en.md +14 -0
- package/README.md +14 -0
- package/dist/cad.js +264 -6
- package/dist/colorMode.d.ts +11 -0
- package/dist/colorMode.js +23 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +5 -4
package/README.en.md
CHANGED
|
@@ -49,3 +49,17 @@ For private deployments, override them with `options.cad.wasmPath`, `options.cad
|
|
|
49
49
|
## Migration Note
|
|
50
50
|
|
|
51
51
|
CAD preview has moved completely out of `@file-viewer/core`. Core now only keeps the asset manifest, shared types, and a compatibility error message, and it no longer installs `@flyfish-dev/cad-viewer` by default. Install this package and pass it through `renderers`, or use `@file-viewer/preset-all` for the complete CAD experience.
|
|
52
|
+
|
|
53
|
+
## Monochrome plot mode
|
|
54
|
+
|
|
55
|
+
Set `cad.colorMode` to `source` or `monochrome`. Monochrome rendering uses the CAD engine's entity-color policy rather than a CSS filter, keeping Canvas, WebGL, text overlays and native DWF output consistent while preserving alpha, line types, line weights and source data.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
{
|
|
59
|
+
cad: {
|
|
60
|
+
colorMode: 'monochrome',
|
|
61
|
+
monochromeColor: '#000000',
|
|
62
|
+
showColorModeToggle: true,
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
```
|
package/README.md
CHANGED
|
@@ -49,3 +49,17 @@ const options = {
|
|
|
49
49
|
## 迁移说明
|
|
50
50
|
|
|
51
51
|
CAD 预览已经从 `@file-viewer/core` 中彻底移出,core 只保留资产 manifest、类型和兼容错误提示,不再默认安装 `@flyfish-dev/cad-viewer`。完整 CAD 能力请安装本包并传入 `renderers`,或直接使用 `@file-viewer/preset-all`。
|
|
52
|
+
|
|
53
|
+
## 黑白出图模式
|
|
54
|
+
|
|
55
|
+
`cad.colorMode` 可设为 `source` 或 `monochrome`。黑白模式通过 CAD 引擎的实体颜色策略实现,不使用 CSS 滤镜,因此 Canvas、WebGL、文字覆盖层及原生 DWF 渲染可保持一致,同时保留透明度、线型、线宽和源文件数据。
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
{
|
|
59
|
+
cad: {
|
|
60
|
+
colorMode: 'monochrome',
|
|
61
|
+
monochromeColor: '#000000',
|
|
62
|
+
showColorModeToggle: true,
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
```
|
package/dist/cad.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { CadViewer, inferEntityKind, } from '@flyfish-dev/cad-viewer';
|
|
2
2
|
import { resolveFileViewerCadAssetUrls, resolveFileViewerRuntimeAssetBaseUrl, } from '@file-viewer/core/assets';
|
|
3
3
|
import { createFileViewerViewStateChange, createFileViewerViewStateChangeEmitter, createFileViewerTranslator, createFileViewerZoomChangeEmitter, registerFileViewerViewStateProvider, registerFileViewerZoomProvider, resolveFileViewerLocale, unregisterFileViewerViewStateProvider, unregisterFileViewerZoomProvider, } from '@file-viewer/core';
|
|
4
|
+
import { applyCadViewerColorMode, normalizeFileViewerCadColorMode, resolveFileViewerCadMonochromeColor, resolveCadViewerSourceDocument, supportsCadViewerColorMode, } from './colorMode.js';
|
|
4
5
|
const CAD_WORKER_TIMEOUT = 120000;
|
|
5
6
|
const CAD_DEFAULT_FIT_PADDING = 0.92;
|
|
6
7
|
const CAD_BOUNDS_EPSILON = 1e-9;
|
|
7
8
|
const CAD_BEST_FIT_OUTLIER_RATIO = 8;
|
|
9
|
+
const CAD_NATIVE_MIN_ZOOM_RATIO = 0.05;
|
|
10
|
+
const CAD_NATIVE_MAX_ZOOM_RATIO = 64;
|
|
8
11
|
const cadStyle = `
|
|
9
12
|
.cad-shell{display:flex;height:100%;min-height:100%;flex-direction:column;background:#f5f7fb;color:#142335}
|
|
10
13
|
.cad-shell *{box-sizing:border-box}
|
|
@@ -12,6 +15,9 @@ const cadStyle = `
|
|
|
12
15
|
.cad-tools,.cad-meta{display:flex;align-items:center;gap:8px}
|
|
13
16
|
.cad-tools button{min-width:34px;min-height:30px;border:0;border-radius:8px;background:rgba(15,23,42,.06);color:#25344c;cursor:pointer;font-weight:800;letter-spacing:0;transition:background-color .18s ease,color .18s ease}
|
|
14
17
|
.cad-tools button:hover{background:rgba(31,150,110,.14);color:#0f8f62}
|
|
18
|
+
.cad-tools button.cad-color-mode{min-width:52px;padding:0 10px;font-size:12px}
|
|
19
|
+
.cad-tools button.cad-color-mode[aria-pressed='true']{background:#0f172a;color:#fff}
|
|
20
|
+
.cad-tools button.cad-color-mode:disabled{cursor:not-allowed;opacity:.46}
|
|
15
21
|
.cad-zoom,.cad-meta span{color:#64748b;font-size:12px;font-weight:800;letter-spacing:0}
|
|
16
22
|
.cad-meta span{border-radius:999px;padding:5px 9px;background:rgba(15,23,42,.06)}
|
|
17
23
|
.cad-body{display:grid;min-height:0;flex:1;grid-template-columns:minmax(176px,236px) minmax(0,1fr) minmax(142px,176px);background:#eef2f7}
|
|
@@ -198,6 +204,105 @@ const getCadDocumentBaseUrl = (target) => {
|
|
|
198
204
|
: 'file:///';
|
|
199
205
|
};
|
|
200
206
|
const CAD_DWG_WORKER_FILENAME = 'file-viewer-input.dwg';
|
|
207
|
+
const getCadPinchSnapshot = (points) => {
|
|
208
|
+
const [first, second] = Array.from(points.values());
|
|
209
|
+
if (!first || !second) {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
center: {
|
|
214
|
+
x: (first.x + second.x) / 2,
|
|
215
|
+
y: (first.y + second.y) / 2,
|
|
216
|
+
},
|
|
217
|
+
distance: Math.hypot(second.x - first.x, second.y - first.y),
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* The bundled CAD engines currently treat every touch pointer as the same
|
|
222
|
+
* drag. Coordinate two touch pointers before their target listeners run so a
|
|
223
|
+
* pinch becomes one anchored zoom operation instead of two competing pans.
|
|
224
|
+
*/
|
|
225
|
+
const registerCadPinchZoom = (surface, onStart, onZoom) => {
|
|
226
|
+
const points = new Map();
|
|
227
|
+
let previous = null;
|
|
228
|
+
let suppressDragUntilRelease = false;
|
|
229
|
+
const suppressPointerEvent = (event) => {
|
|
230
|
+
event.preventDefault();
|
|
231
|
+
event.stopImmediatePropagation();
|
|
232
|
+
};
|
|
233
|
+
const handlePointerDown = (event) => {
|
|
234
|
+
if (event.pointerType !== 'touch') {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
points.set(event.pointerId, { x: event.clientX, y: event.clientY });
|
|
238
|
+
try {
|
|
239
|
+
surface.setPointerCapture(event.pointerId);
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// Synthetic browser harness events may not create an active pointer.
|
|
243
|
+
}
|
|
244
|
+
if (points.size < 2) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
suppressDragUntilRelease = true;
|
|
248
|
+
previous = getCadPinchSnapshot(points);
|
|
249
|
+
onStart();
|
|
250
|
+
suppressPointerEvent(event);
|
|
251
|
+
};
|
|
252
|
+
const handlePointerMove = (event) => {
|
|
253
|
+
if (event.pointerType !== 'touch' || !points.has(event.pointerId)) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
points.set(event.pointerId, { x: event.clientX, y: event.clientY });
|
|
257
|
+
if (!suppressDragUntilRelease) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (points.size >= 2) {
|
|
261
|
+
const current = getCadPinchSnapshot(points);
|
|
262
|
+
if (previous && current && previous.distance > 0 && current.distance > 0) {
|
|
263
|
+
onZoom({
|
|
264
|
+
center: current.center,
|
|
265
|
+
deltaX: current.center.x - previous.center.x,
|
|
266
|
+
deltaY: current.center.y - previous.center.y,
|
|
267
|
+
factor: Math.min(2, Math.max(0.5, current.distance / previous.distance)),
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
previous = current;
|
|
271
|
+
}
|
|
272
|
+
suppressPointerEvent(event);
|
|
273
|
+
};
|
|
274
|
+
const handlePointerEnd = (event) => {
|
|
275
|
+
if (event.pointerType !== 'touch' || !points.has(event.pointerId)) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
points.delete(event.pointerId);
|
|
279
|
+
previous = points.size >= 2 ? getCadPinchSnapshot(points) : null;
|
|
280
|
+
if (points.size === 0) {
|
|
281
|
+
suppressDragUntilRelease = false;
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
if (surface.hasPointerCapture(event.pointerId)) {
|
|
285
|
+
surface.releasePointerCapture(event.pointerId);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
// The underlying engine may already have released this pointer.
|
|
290
|
+
}
|
|
291
|
+
// Do not stop pointerup/cancel: the engine must clear the single-pointer
|
|
292
|
+
// drag that began before the second finger started the pinch.
|
|
293
|
+
};
|
|
294
|
+
surface.addEventListener('pointerdown', handlePointerDown, { capture: true });
|
|
295
|
+
surface.addEventListener('pointermove', handlePointerMove, { capture: true });
|
|
296
|
+
surface.addEventListener('pointerup', handlePointerEnd, { capture: true });
|
|
297
|
+
surface.addEventListener('pointercancel', handlePointerEnd, { capture: true });
|
|
298
|
+
return () => {
|
|
299
|
+
surface.removeEventListener('pointerdown', handlePointerDown, { capture: true });
|
|
300
|
+
surface.removeEventListener('pointermove', handlePointerMove, { capture: true });
|
|
301
|
+
surface.removeEventListener('pointerup', handlePointerEnd, { capture: true });
|
|
302
|
+
surface.removeEventListener('pointercancel', handlePointerEnd, { capture: true });
|
|
303
|
+
points.clear();
|
|
304
|
+
};
|
|
305
|
+
};
|
|
201
306
|
const createEmptyCadBounds = () => ({
|
|
202
307
|
minX: Number.POSITIVE_INFINITY,
|
|
203
308
|
minY: Number.POSITIVE_INFINITY,
|
|
@@ -547,6 +652,8 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
547
652
|
const options = ((_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.cad) || {};
|
|
548
653
|
const t = createFileViewerTranslator(context === null || context === void 0 ? void 0 : context.options);
|
|
549
654
|
const locale = resolveFileViewerLocale(context === null || context === void 0 ? void 0 : context.options);
|
|
655
|
+
const monochromeColor = resolveFileViewerCadMonochromeColor(options.monochromeColor);
|
|
656
|
+
let colorMode = normalizeFileViewerCadColorMode(options.colorMode);
|
|
550
657
|
let status = 'loading';
|
|
551
658
|
let progressMessage = t('cad.state.loadingViewer');
|
|
552
659
|
let errorMessage = '';
|
|
@@ -557,7 +664,10 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
557
664
|
let viewer = null;
|
|
558
665
|
let resizeObserver = null;
|
|
559
666
|
let abortController = null;
|
|
667
|
+
let disposeCadPinch = null;
|
|
668
|
+
let disposeNativeInteractions = null;
|
|
560
669
|
let fitViewActive = true;
|
|
670
|
+
let nativeZoomRatio = 1;
|
|
561
671
|
let disposed = false;
|
|
562
672
|
const style = createStyle();
|
|
563
673
|
const shell = createElement('div', 'cad-shell');
|
|
@@ -568,16 +678,18 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
568
678
|
const zoomOutButton = createElement('button', undefined, '-');
|
|
569
679
|
const zoomText = createElement('span', 'cad-zoom', '100%');
|
|
570
680
|
const zoomInButton = createElement('button', undefined, '+');
|
|
681
|
+
const colorModeButton = createElement('button', 'cad-color-mode');
|
|
682
|
+
colorModeButton.hidden = options.showColorModeToggle === false;
|
|
571
683
|
const meta = createElement('div', 'cad-meta');
|
|
572
684
|
const typeMeta = createElement('span', undefined, normalizedType.toUpperCase());
|
|
573
685
|
const backendMeta = createElement('span', undefined, 'AUTO');
|
|
574
|
-
[fitButton, zoomOutButton, zoomInButton].forEach(button => {
|
|
686
|
+
[fitButton, zoomOutButton, zoomInButton, colorModeButton].forEach(button => {
|
|
575
687
|
button.type = 'button';
|
|
576
688
|
});
|
|
577
689
|
fitButton.title = t('cad.toolbar.fit');
|
|
578
690
|
zoomOutButton.title = t('cad.toolbar.zoomOut');
|
|
579
691
|
zoomInButton.title = t('cad.toolbar.zoomIn');
|
|
580
|
-
tools.append(fitButton, zoomOutButton, zoomText, zoomInButton);
|
|
692
|
+
tools.append(fitButton, zoomOutButton, zoomText, zoomInButton, colorModeButton);
|
|
581
693
|
meta.append(typeMeta, backendMeta);
|
|
582
694
|
toolbar.append(tools, meta);
|
|
583
695
|
const body = createElement('div', 'cad-body without-layers');
|
|
@@ -615,8 +727,11 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
615
727
|
};
|
|
616
728
|
const getWarnings = () => (loadResult === null || loadResult === void 0 ? void 0 : loadResult.warnings) || (loadResult === null || loadResult === void 0 ? void 0 : loadResult.document.warnings) || [];
|
|
617
729
|
const getZoomPercent = () => {
|
|
618
|
-
var _a, _b, _c;
|
|
619
|
-
|
|
730
|
+
var _a, _b, _c, _d;
|
|
731
|
+
if ((_a = viewer === null || viewer === void 0 ? void 0 : viewer.isNativeRendererActive) === null || _a === void 0 ? void 0 : _a.call(viewer)) {
|
|
732
|
+
return Math.round(nativeZoomRatio * 100);
|
|
733
|
+
}
|
|
734
|
+
const zoom = (_d = (_b = viewState === null || viewState === void 0 ? void 0 : viewState.zoomPercent) !== null && _b !== void 0 ? _b : (_c = viewer === null || viewer === void 0 ? void 0 : viewer.getZoomPercent) === null || _c === void 0 ? void 0 : _c.call(viewer)) !== null && _d !== void 0 ? _d : 100;
|
|
620
735
|
return Number.isFinite(zoom) ? Math.round(zoom) : 100;
|
|
621
736
|
};
|
|
622
737
|
const getCadZoomState = () => {
|
|
@@ -642,6 +757,8 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
642
757
|
status,
|
|
643
758
|
view: viewState ? { ...viewState } : null,
|
|
644
759
|
backend: renderStats === null || renderStats === void 0 ? void 0 : renderStats.backend,
|
|
760
|
+
colorMode,
|
|
761
|
+
monochromeColor: colorMode === 'monochrome' ? monochromeColor : undefined,
|
|
645
762
|
layerCount: layers.length,
|
|
646
763
|
visibleLayers: layers
|
|
647
764
|
.filter(layer => layer.isVisible !== false && !layer.isFrozen)
|
|
@@ -655,6 +772,98 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
655
772
|
}
|
|
656
773
|
return state;
|
|
657
774
|
};
|
|
775
|
+
const clampNativeZoomRatio = (ratio) => {
|
|
776
|
+
return Math.min(CAD_NATIVE_MAX_ZOOM_RATIO, Math.max(CAD_NATIVE_MIN_ZOOM_RATIO, ratio));
|
|
777
|
+
};
|
|
778
|
+
const notifyNativeZoomChange = (action) => {
|
|
779
|
+
cadZoomEmitter.emit();
|
|
780
|
+
syncState();
|
|
781
|
+
emitCadViewStateChange(action, 'user');
|
|
782
|
+
};
|
|
783
|
+
const bindNativeCadInteractions = () => {
|
|
784
|
+
disposeNativeInteractions === null || disposeNativeInteractions === void 0 ? void 0 : disposeNativeInteractions();
|
|
785
|
+
disposeNativeInteractions = null;
|
|
786
|
+
const surface = nativeHost.querySelector('.dwfv-overlay-canvas');
|
|
787
|
+
if (!surface) {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
let notificationQueued = false;
|
|
791
|
+
const queueNativeZoomChange = (action) => {
|
|
792
|
+
if (notificationQueued) {
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
notificationQueued = true;
|
|
796
|
+
queueMicrotask(() => {
|
|
797
|
+
var _a;
|
|
798
|
+
notificationQueued = false;
|
|
799
|
+
if (!disposed && ((_a = viewer === null || viewer === void 0 ? void 0 : viewer.isNativeRendererActive) === null || _a === void 0 ? void 0 : _a.call(viewer))) {
|
|
800
|
+
notifyNativeZoomChange(action);
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
};
|
|
804
|
+
const applyNativeZoomFactor = (factor, action) => {
|
|
805
|
+
if (!Number.isFinite(factor) || factor <= 0) {
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
nativeZoomRatio = clampNativeZoomRatio(nativeZoomRatio * factor);
|
|
809
|
+
queueNativeZoomChange(action);
|
|
810
|
+
};
|
|
811
|
+
const handleNativeClick = (event) => {
|
|
812
|
+
const eventTarget = event.target;
|
|
813
|
+
const button = eventTarget instanceof Element ? eventTarget.closest('button') : null;
|
|
814
|
+
if (!button || !nativeHost.contains(button)) {
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
const label = (button.textContent || '').trim();
|
|
818
|
+
if (label === '+') {
|
|
819
|
+
applyNativeZoomFactor(1.25, 'zoom-in');
|
|
820
|
+
}
|
|
821
|
+
else if (label === '-' || label === '−') {
|
|
822
|
+
applyNativeZoomFactor(0.8, 'zoom-out');
|
|
823
|
+
}
|
|
824
|
+
else if (/适应|fit|reset/i.test(label)) {
|
|
825
|
+
nativeZoomRatio = 1;
|
|
826
|
+
queueNativeZoomChange('zoom-reset');
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
const handleNativeWheel = (event) => {
|
|
830
|
+
const rect = surface.getBoundingClientRect();
|
|
831
|
+
const delta = event.deltaMode === WheelEvent.DOM_DELTA_LINE
|
|
832
|
+
? event.deltaY * 16
|
|
833
|
+
: event.deltaMode === WheelEvent.DOM_DELTA_PAGE
|
|
834
|
+
? event.deltaY * Math.max(1, rect.height)
|
|
835
|
+
: event.deltaY;
|
|
836
|
+
applyNativeZoomFactor(Math.exp(-delta * 0.0015), 'cad-view-change');
|
|
837
|
+
};
|
|
838
|
+
const handleNativePageChange = (event) => {
|
|
839
|
+
if (event.target instanceof HTMLSelectElement && nativeHost.contains(event.target)) {
|
|
840
|
+
nativeZoomRatio = 1;
|
|
841
|
+
queueNativeZoomChange('zoom-reset');
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
const disposePinch = registerCadPinchZoom(surface, () => {
|
|
845
|
+
fitViewActive = false;
|
|
846
|
+
}, ({ center, factor }) => {
|
|
847
|
+
const deltaY = -Math.log(factor) / 0.0015;
|
|
848
|
+
surface.dispatchEvent(new WheelEvent('wheel', {
|
|
849
|
+
bubbles: true,
|
|
850
|
+
cancelable: true,
|
|
851
|
+
clientX: center.x,
|
|
852
|
+
clientY: center.y,
|
|
853
|
+
deltaMode: WheelEvent.DOM_DELTA_PIXEL,
|
|
854
|
+
deltaY,
|
|
855
|
+
}));
|
|
856
|
+
});
|
|
857
|
+
nativeHost.addEventListener('click', handleNativeClick);
|
|
858
|
+
nativeHost.addEventListener('change', handleNativePageChange);
|
|
859
|
+
surface.addEventListener('wheel', handleNativeWheel);
|
|
860
|
+
disposeNativeInteractions = () => {
|
|
861
|
+
disposePinch();
|
|
862
|
+
nativeHost.removeEventListener('click', handleNativeClick);
|
|
863
|
+
nativeHost.removeEventListener('change', handleNativePageChange);
|
|
864
|
+
surface.removeEventListener('wheel', handleNativeWheel);
|
|
865
|
+
};
|
|
866
|
+
};
|
|
658
867
|
const syncInspector = () => {
|
|
659
868
|
const summary = loadResult === null || loadResult === void 0 ? void 0 : loadResult.summary;
|
|
660
869
|
const rows = [
|
|
@@ -686,12 +895,15 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
686
895
|
: layer.name;
|
|
687
896
|
button.setAttribute('aria-pressed', String(layerVisible));
|
|
688
897
|
const color = createElement('span', 'cad-layer-color');
|
|
689
|
-
if (
|
|
898
|
+
if (colorMode === 'monochrome') {
|
|
899
|
+
color.style.background = monochromeColor;
|
|
900
|
+
}
|
|
901
|
+
else if (typeof layer.color === 'string') {
|
|
690
902
|
color.style.background = layer.color;
|
|
691
903
|
}
|
|
692
904
|
button.append(color, createElement('span', undefined, layer.name));
|
|
693
905
|
button.addEventListener('click', () => {
|
|
694
|
-
const document = viewer
|
|
906
|
+
const document = resolveCadViewerSourceDocument(viewer);
|
|
695
907
|
if (!document) {
|
|
696
908
|
return;
|
|
697
909
|
}
|
|
@@ -718,6 +930,15 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
718
930
|
const syncState = () => {
|
|
719
931
|
zoomText.textContent = `${getZoomPercent()}%`;
|
|
720
932
|
backendMeta.textContent = ((renderStats === null || renderStats === void 0 ? void 0 : renderStats.backend) || 'auto').toUpperCase();
|
|
933
|
+
const colorModeSupported = supportsCadViewerColorMode(viewer);
|
|
934
|
+
colorModeButton.disabled = status !== 'ready' || !colorModeSupported;
|
|
935
|
+
colorModeButton.setAttribute('aria-pressed', String(colorMode === 'monochrome'));
|
|
936
|
+
colorModeButton.textContent = t(colorMode === 'monochrome'
|
|
937
|
+
? 'cad.toolbar.monochrome'
|
|
938
|
+
: 'cad.toolbar.colorSource');
|
|
939
|
+
colorModeButton.title = t(colorMode === 'monochrome'
|
|
940
|
+
? 'cad.toolbar.colorSource'
|
|
941
|
+
: 'cad.toolbar.monochrome');
|
|
721
942
|
state.hidden = status === 'ready';
|
|
722
943
|
state.classList.toggle('error', status === 'error');
|
|
723
944
|
if (status === 'loading') {
|
|
@@ -744,6 +965,7 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
744
965
|
return false;
|
|
745
966
|
}
|
|
746
967
|
if ((_a = viewer.isNativeRendererActive) === null || _a === void 0 ? void 0 : _a.call(viewer)) {
|
|
968
|
+
nativeZoomRatio = 1;
|
|
747
969
|
viewer.fit();
|
|
748
970
|
return true;
|
|
749
971
|
}
|
|
@@ -854,6 +1076,17 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
854
1076
|
fitButton.addEventListener('click', () => fitToView());
|
|
855
1077
|
zoomInButton.addEventListener('click', zoomIn);
|
|
856
1078
|
zoomOutButton.addEventListener('click', zoomOut);
|
|
1079
|
+
colorModeButton.addEventListener('click', () => {
|
|
1080
|
+
const previousMode = colorMode;
|
|
1081
|
+
colorMode = colorMode === 'monochrome' ? 'source' : 'monochrome';
|
|
1082
|
+
if (!applyCadViewerColorMode(viewer, colorMode, monochromeColor)) {
|
|
1083
|
+
colorMode = previousMode;
|
|
1084
|
+
syncState();
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
syncUi();
|
|
1088
|
+
emitCadViewStateChange('cad-view-change', 'user');
|
|
1089
|
+
});
|
|
857
1090
|
const createViewer = () => {
|
|
858
1091
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
859
1092
|
const { wasmPath, workerUrl, dwfWasmUrl } = resolveFileViewerCadAssetUrls(options, getCadDocumentBaseUrl(target));
|
|
@@ -894,6 +1127,7 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
894
1127
|
dwfMaxOverviewStrokeCssPx: options.dwfMaxOverviewStrokeCssPx,
|
|
895
1128
|
dwfMinTextCssPx: options.dwfMinTextCssPx,
|
|
896
1129
|
dwfMinFilledAreaCssPx: options.dwfMinFilledAreaCssPx,
|
|
1130
|
+
...{ colorMode, monochromeColor },
|
|
897
1131
|
autoFit: true,
|
|
898
1132
|
canvasOptions,
|
|
899
1133
|
onLoadProgress: updateProgress,
|
|
@@ -918,6 +1152,19 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
918
1152
|
syncState();
|
|
919
1153
|
},
|
|
920
1154
|
});
|
|
1155
|
+
disposeCadPinch === null || disposeCadPinch === void 0 ? void 0 : disposeCadPinch();
|
|
1156
|
+
const renderer = nextViewer.renderer;
|
|
1157
|
+
disposeCadPinch = registerCadPinchZoom(nextViewer.canvas, () => {
|
|
1158
|
+
fitViewActive = false;
|
|
1159
|
+
}, ({ center, deltaX, deltaY, factor }) => {
|
|
1160
|
+
var _a, _b;
|
|
1161
|
+
const rect = nextViewer.canvas.getBoundingClientRect();
|
|
1162
|
+
(_a = renderer.panByScreenDelta) === null || _a === void 0 ? void 0 : _a.call(renderer, deltaX, deltaY);
|
|
1163
|
+
(_b = renderer.zoom) === null || _b === void 0 ? void 0 : _b.call(renderer, factor, {
|
|
1164
|
+
x: center.x - rect.left,
|
|
1165
|
+
y: center.y - rect.top,
|
|
1166
|
+
});
|
|
1167
|
+
});
|
|
921
1168
|
if (options.preloadDwg !== false && normalizedType === 'dwg') {
|
|
922
1169
|
void nextViewer.preloadDwg({ wasmPath, workerUrl }).catch(() => {
|
|
923
1170
|
// 预热失败不阻断真实加载,loadBuffer 会返回完整错误上下文。
|
|
@@ -926,6 +1173,7 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
926
1173
|
return nextViewer;
|
|
927
1174
|
};
|
|
928
1175
|
const loadCad = async () => {
|
|
1176
|
+
var _a;
|
|
929
1177
|
status = 'loading';
|
|
930
1178
|
progressMessage = t('cad.state.parsing');
|
|
931
1179
|
errorMessage = '';
|
|
@@ -934,6 +1182,9 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
934
1182
|
viewState = null;
|
|
935
1183
|
layers = [];
|
|
936
1184
|
fitViewActive = true;
|
|
1185
|
+
nativeZoomRatio = 1;
|
|
1186
|
+
disposeNativeInteractions === null || disposeNativeInteractions === void 0 ? void 0 : disposeNativeInteractions();
|
|
1187
|
+
disposeNativeInteractions = null;
|
|
937
1188
|
syncUi();
|
|
938
1189
|
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
939
1190
|
const controller = new AbortController();
|
|
@@ -956,6 +1207,9 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
956
1207
|
loadResult = restoreLoadResultSourceName(result);
|
|
957
1208
|
layers = collectLayers(result);
|
|
958
1209
|
status = 'ready';
|
|
1210
|
+
if ((_a = viewer.isNativeRendererActive) === null || _a === void 0 ? void 0 : _a.call(viewer)) {
|
|
1211
|
+
bindNativeCadInteractions();
|
|
1212
|
+
}
|
|
959
1213
|
syncUi();
|
|
960
1214
|
queueMicrotask(() => {
|
|
961
1215
|
applyCadFit();
|
|
@@ -999,6 +1253,10 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
|
|
|
999
1253
|
unregisterFileViewerZoomProvider(shell);
|
|
1000
1254
|
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
1001
1255
|
abortController = null;
|
|
1256
|
+
disposeCadPinch === null || disposeCadPinch === void 0 ? void 0 : disposeCadPinch();
|
|
1257
|
+
disposeCadPinch = null;
|
|
1258
|
+
disposeNativeInteractions === null || disposeNativeInteractions === void 0 ? void 0 : disposeNativeInteractions();
|
|
1259
|
+
disposeNativeInteractions = null;
|
|
1002
1260
|
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
|
|
1003
1261
|
resizeObserver = null;
|
|
1004
1262
|
viewer === null || viewer === void 0 ? void 0 : viewer.destroy();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FileViewerCadColorMode } from '@file-viewer/core';
|
|
2
|
+
export interface CadViewerColorModeAdapter {
|
|
3
|
+
setColorMode?: (mode: FileViewerCadColorMode, monochromeColor?: string) => void;
|
|
4
|
+
getColorMode?: () => FileViewerCadColorMode;
|
|
5
|
+
getMonochromeColor?: () => string | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare function normalizeFileViewerCadColorMode(value: unknown): FileViewerCadColorMode;
|
|
8
|
+
export declare function resolveFileViewerCadMonochromeColor(value: unknown, fallback?: string): string;
|
|
9
|
+
export declare function supportsCadViewerColorMode(value: unknown): value is CadViewerColorModeAdapter;
|
|
10
|
+
export declare function resolveCadViewerSourceDocument(viewer: unknown): unknown;
|
|
11
|
+
export declare function applyCadViewerColorMode(viewer: unknown, mode: FileViewerCadColorMode, monochromeColor: string): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function normalizeFileViewerCadColorMode(value) {
|
|
2
|
+
return value === 'monochrome' ? 'monochrome' : 'source';
|
|
3
|
+
}
|
|
4
|
+
export function resolveFileViewerCadMonochromeColor(value, fallback = '#000000') {
|
|
5
|
+
if (typeof value === 'string' && value.trim())
|
|
6
|
+
return value.trim();
|
|
7
|
+
return fallback;
|
|
8
|
+
}
|
|
9
|
+
export function supportsCadViewerColorMode(value) {
|
|
10
|
+
return Boolean(value && typeof value.setColorMode === 'function');
|
|
11
|
+
}
|
|
12
|
+
export function resolveCadViewerSourceDocument(viewer) {
|
|
13
|
+
var _a, _b, _c;
|
|
14
|
+
const candidate = viewer;
|
|
15
|
+
return (_b = (_a = candidate === null || candidate === void 0 ? void 0 : candidate.getSourceDocument) === null || _a === void 0 ? void 0 : _a.call(candidate)) !== null && _b !== void 0 ? _b : (_c = candidate === null || candidate === void 0 ? void 0 : candidate.getDocument) === null || _c === void 0 ? void 0 : _c.call(candidate);
|
|
16
|
+
}
|
|
17
|
+
export function applyCadViewerColorMode(viewer, mode, monochromeColor) {
|
|
18
|
+
var _a;
|
|
19
|
+
if (!supportsCadViewerColorMode(viewer))
|
|
20
|
+
return false;
|
|
21
|
+
(_a = viewer.setColorMode) === null || _a === void 0 ? void 0 : _a.call(viewer, mode, monochromeColor);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type FileRenderHandler, type FileViewerRenderedInstance, type FileViewerRendererPlugin, type RendererDefinition } from '@file-viewer/core';
|
|
2
|
+
export { applyCadViewerColorMode, normalizeFileViewerCadColorMode, resolveCadViewerSourceDocument, resolveFileViewerCadMonochromeColor, supportsCadViewerColorMode, } from './colorMode.js';
|
|
3
|
+
export type { CadViewerColorModeAdapter } from './colorMode.js';
|
|
2
4
|
export declare const cadRendererDefinition: RendererDefinition;
|
|
3
5
|
export declare const renderFileViewerCad: FileRenderHandler<FileViewerRenderedInstance, HTMLDivElement>;
|
|
4
6
|
export declare const cadRenderer: FileViewerRendererPlugin<FileRenderHandler<FileViewerRenderedInstance, HTMLDivElement>>;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_RENDERER_DEFINITIONS, } from '@file-viewer/core';
|
|
2
|
+
export { applyCadViewerColorMode, normalizeFileViewerCadColorMode, resolveCadViewerSourceDocument, resolveFileViewerCadMonochromeColor, supportsCadViewerColorMode, } from './colorMode.js';
|
|
2
3
|
const cadDefinition = DEFAULT_RENDERER_DEFINITIONS.find(definition => definition.id === 'cad');
|
|
3
4
|
if (!cadDefinition) {
|
|
4
5
|
throw new Error('@file-viewer/renderer-cad could not locate the shared CAD format definition.');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/renderer-cad",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone CAD renderer plugin for File Viewer powered by @flyfish-dev/cad-viewer.",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
"LICENSE"
|
|
57
57
|
],
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@file-viewer/core": "3.0.
|
|
60
|
-
"@flyfish-dev/cad-viewer": "0.8.
|
|
59
|
+
"@file-viewer/core": "3.0.2",
|
|
60
|
+
"@flyfish-dev/cad-viewer": "0.8.1"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"typescript": "^6.0.3"
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"license": "Apache-2.0",
|
|
66
66
|
"scripts": {
|
|
67
67
|
"build": "tsc -b tsconfig.json",
|
|
68
|
-
"type-check": "tsc -b tsconfig.json"
|
|
68
|
+
"type-check": "tsc -b tsconfig.json",
|
|
69
|
+
"verify:color-mode": "node scripts/verify-color-mode.mjs"
|
|
69
70
|
}
|
|
70
71
|
}
|