react-os-shell 2.3.0 → 2.5.0
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/Browser-PH57GK7S.js +7 -0
- package/dist/{Browser-SP6PGPN5.js.map → Browser-PH57GK7S.js.map} +1 -1
- package/dist/{Calculator-XGXSRMF2.js → Calculator-H7HMALL3.js} +4 -4
- package/dist/{Calculator-XGXSRMF2.js.map → Calculator-H7HMALL3.js.map} +1 -1
- package/dist/{CurrencyConverter-SVYA7ZGT.js → CurrencyConverter-576WXG7B.js} +4 -4
- package/dist/{CurrencyConverter-SVYA7ZGT.js.map → CurrencyConverter-576WXG7B.js.map} +1 -1
- package/dist/{Documents-QXF5BF3N.js → Documents-3SXOEFIQ.js} +4 -4
- package/dist/{Documents-QXF5BF3N.js.map → Documents-3SXOEFIQ.js.map} +1 -1
- package/dist/Files-YIYWFGHQ.js +13 -0
- package/dist/{Files-JUO4Q7WI.js.map → Files-YIYWFGHQ.js.map} +1 -1
- package/dist/{Notepad-EQ5YTHYQ.js → Notepad-BZBRXG43.js} +4 -4
- package/dist/{Notepad-EQ5YTHYQ.js.map → Notepad-BZBRXG43.js.map} +1 -1
- package/dist/{PomodoroTimer-L62PEYPP.js → PomodoroTimer-PQ7FXSKY.js} +4 -4
- package/dist/{PomodoroTimer-L62PEYPP.js.map → PomodoroTimer-PQ7FXSKY.js.map} +1 -1
- package/dist/Preview-L5ABFUSO.js +9 -0
- package/dist/{Preview-FHEOYNOR.js.map → Preview-L5ABFUSO.js.map} +1 -1
- package/dist/Spreadsheet-WDMPVUDW.js +7 -0
- package/dist/{Spreadsheet-Q2YHXKP4.js.map → Spreadsheet-WDMPVUDW.js.map} +1 -1
- package/dist/{Stock-EDXEPZFF.js → Stock-NQFKY52J.js} +4 -4
- package/dist/{Stock-EDXEPZFF.js.map → Stock-NQFKY52J.js.map} +1 -1
- package/dist/{Weather-T2EVJ5NE.js → Weather-KH5A7AZ3.js} +4 -4
- package/dist/{Weather-T2EVJ5NE.js.map → Weather-KH5A7AZ3.js.map} +1 -1
- package/dist/{WorldClock-JN7YJN3B.js → WorldClock-VUMFYV5V.js} +4 -4
- package/dist/{WorldClock-JN7YJN3B.js.map → WorldClock-VUMFYV5V.js.map} +1 -1
- package/dist/apps/index.js +19 -19
- package/dist/{chunk-FISSBIJU.js → chunk-6YJFK6H3.js} +4 -4
- package/dist/{chunk-FISSBIJU.js.map → chunk-6YJFK6H3.js.map} +1 -1
- package/dist/{chunk-KGDRIEI4.js → chunk-7CXMEEUA.js} +5 -5
- package/dist/{chunk-KGDRIEI4.js.map → chunk-7CXMEEUA.js.map} +1 -1
- package/dist/{chunk-G5VOT4ER.js → chunk-FPOVTUH2.js} +4 -4
- package/dist/{chunk-G5VOT4ER.js.map → chunk-FPOVTUH2.js.map} +1 -1
- package/dist/{chunk-IBNOPYS4.js → chunk-QMX4QCJG.js} +4 -4
- package/dist/{chunk-IBNOPYS4.js.map → chunk-QMX4QCJG.js.map} +1 -1
- package/dist/{chunk-7YHB7JZ3.js → chunk-QQ3K3EMW.js} +6 -6
- package/dist/{chunk-7YHB7JZ3.js.map → chunk-QQ3K3EMW.js.map} +1 -1
- package/dist/{chunk-QAHF22KW.js → chunk-TJ6N7SI5.js} +24 -3
- package/dist/chunk-TJ6N7SI5.js.map +1 -0
- package/dist/{chunk-4LQVJQ3S.js → chunk-UFTJG6IM.js} +682 -127
- package/dist/chunk-UFTJG6IM.js.map +1 -0
- package/dist/{chunk-5V6OCGI6.js → chunk-YVIW5GPB.js} +3 -3
- package/dist/{chunk-5V6OCGI6.js.map → chunk-YVIW5GPB.js.map} +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.js +25 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/Browser-SP6PGPN5.js +0 -7
- package/dist/Files-JUO4Q7WI.js +0 -13
- package/dist/Preview-FHEOYNOR.js +0 -9
- package/dist/Spreadsheet-Q2YHXKP4.js +0 -7
- package/dist/chunk-4LQVJQ3S.js.map +0 -1
- package/dist/chunk-QAHF22KW.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ImageAnnotator_default } from './chunk-KUIPWCTJ.js';
|
|
2
2
|
import { toast_default } from './chunk-WIJ45SYD.js';
|
|
3
|
-
import { AboutApp } from './chunk-
|
|
4
|
-
import { WindowTitle, getActiveModalId } from './chunk-
|
|
3
|
+
import { AboutApp } from './chunk-QQ3K3EMW.js';
|
|
4
|
+
import { WindowTitle, registerModalEscapeInterceptor, getActiveModalId } from './chunk-TJ6N7SI5.js';
|
|
5
5
|
import { createContext, useRef, useEffect, useState, useContext } from 'react';
|
|
6
6
|
import { createPortal } from 'react-dom';
|
|
7
7
|
import * as pdfjsLib from 'pdfjs-dist';
|
|
@@ -263,8 +263,65 @@ function ConvertingPanel({ filename, message }) {
|
|
|
263
263
|
] });
|
|
264
264
|
}
|
|
265
265
|
var ZOOM_PRESETS = [50, 75, 100, 125, 150, 200, 300, 400];
|
|
266
|
+
var TEXT_LAYER_CSS = `
|
|
267
|
+
.preview-pdf-textlayer {
|
|
268
|
+
position: absolute;
|
|
269
|
+
inset: 0;
|
|
270
|
+
overflow: clip;
|
|
271
|
+
line-height: 1;
|
|
272
|
+
text-align: initial;
|
|
273
|
+
text-size-adjust: none;
|
|
274
|
+
forced-color-adjust: none;
|
|
275
|
+
transform-origin: 0 0;
|
|
276
|
+
caret-color: CanvasText;
|
|
277
|
+
--min-font-size: 1;
|
|
278
|
+
--text-scale-factor: calc(var(--total-scale-factor, 1) * var(--min-font-size));
|
|
279
|
+
--min-font-size-inv: calc(1 / var(--min-font-size));
|
|
280
|
+
}
|
|
281
|
+
.preview-pdf-textlayer :is(span, br) {
|
|
282
|
+
color: transparent;
|
|
283
|
+
position: absolute;
|
|
284
|
+
white-space: pre;
|
|
285
|
+
cursor: text;
|
|
286
|
+
transform-origin: 0% 0%;
|
|
287
|
+
}
|
|
288
|
+
.preview-pdf-textlayer > :not(.markedContent),
|
|
289
|
+
.preview-pdf-textlayer .markedContent span:not(.markedContent) {
|
|
290
|
+
z-index: 1;
|
|
291
|
+
--font-height: 0;
|
|
292
|
+
font-size: calc(var(--text-scale-factor) * var(--font-height));
|
|
293
|
+
--scale-x: 1;
|
|
294
|
+
--rotate: 0deg;
|
|
295
|
+
transform: rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv));
|
|
296
|
+
}
|
|
297
|
+
.preview-pdf-textlayer .markedContent {
|
|
298
|
+
display: contents;
|
|
299
|
+
}
|
|
300
|
+
.preview-pdf-textlayer span[role="img"] {
|
|
301
|
+
user-select: none;
|
|
302
|
+
cursor: default;
|
|
303
|
+
}
|
|
304
|
+
.preview-pdf-textlayer ::selection {
|
|
305
|
+
background: rgba(0, 80, 255, 0.25);
|
|
306
|
+
}
|
|
307
|
+
.preview-pdf-textlayer br::selection {
|
|
308
|
+
background: transparent;
|
|
309
|
+
}
|
|
310
|
+
.preview-pdf-textlayer .endOfContent {
|
|
311
|
+
display: block;
|
|
312
|
+
position: absolute;
|
|
313
|
+
inset: 100% 0 0;
|
|
314
|
+
z-index: 0;
|
|
315
|
+
cursor: default;
|
|
316
|
+
user-select: none;
|
|
317
|
+
}
|
|
318
|
+
.preview-pdf-textlayer.selecting .endOfContent {
|
|
319
|
+
top: 0;
|
|
320
|
+
}
|
|
321
|
+
`;
|
|
266
322
|
function PdfPanel({ url, filename, onDownload, onEmail }) {
|
|
267
323
|
const canvasRef = useRef(null);
|
|
324
|
+
const textLayerRef = useRef(null);
|
|
268
325
|
const containerRef = useRef(null);
|
|
269
326
|
const [pdf, setPdf] = useState(null);
|
|
270
327
|
const [page, setPage] = useState(1);
|
|
@@ -310,6 +367,7 @@ function PdfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
310
367
|
if (!pdf || !canvasRef.current) return;
|
|
311
368
|
let cancelled = false;
|
|
312
369
|
let task = null;
|
|
370
|
+
let textLayer = null;
|
|
313
371
|
pdf.getPage(page).then((p) => {
|
|
314
372
|
if (cancelled || !canvasRef.current) return;
|
|
315
373
|
const viewport = p.getViewport({ scale });
|
|
@@ -322,12 +380,35 @@ function PdfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
322
380
|
task = p.render({ canvas, canvasContext: ctx, viewport });
|
|
323
381
|
task.promise.catch(() => {
|
|
324
382
|
});
|
|
383
|
+
const textEl = textLayerRef.current;
|
|
384
|
+
if (textEl) {
|
|
385
|
+
textEl.replaceChildren();
|
|
386
|
+
textEl.style.setProperty("--total-scale-factor", String(viewport.scale));
|
|
387
|
+
textLayer = new pdfjsLib.TextLayer({
|
|
388
|
+
textContentSource: p.streamTextContent(),
|
|
389
|
+
container: textEl,
|
|
390
|
+
viewport
|
|
391
|
+
});
|
|
392
|
+
textLayer.render().then(() => {
|
|
393
|
+
if (cancelled) return;
|
|
394
|
+
const end = document.createElement("div");
|
|
395
|
+
end.className = "endOfContent";
|
|
396
|
+
textEl.append(end);
|
|
397
|
+
}).catch(() => {
|
|
398
|
+
});
|
|
399
|
+
}
|
|
325
400
|
});
|
|
326
401
|
return () => {
|
|
327
402
|
cancelled = true;
|
|
328
403
|
task?.cancel();
|
|
404
|
+
textLayer?.cancel();
|
|
329
405
|
};
|
|
330
406
|
}, [pdf, page, scale]);
|
|
407
|
+
useEffect(() => {
|
|
408
|
+
const up = () => textLayerRef.current?.classList.remove("selecting");
|
|
409
|
+
window.addEventListener("pointerup", up);
|
|
410
|
+
return () => window.removeEventListener("pointerup", up);
|
|
411
|
+
}, []);
|
|
331
412
|
const handlePrint = () => {
|
|
332
413
|
if (!pdf) return;
|
|
333
414
|
const win = window.open("", "_blank");
|
|
@@ -500,7 +581,20 @@ function PdfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
500
581
|
tabIndex: 0,
|
|
501
582
|
onWheel: onWheelPage,
|
|
502
583
|
onKeyDown: onKeyPage,
|
|
503
|
-
children: loading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full text-gray-400 text-sm", children: "Loading PDF..." }) : /* @__PURE__ */
|
|
584
|
+
children: loading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full text-gray-400 text-sm", children: "Loading PDF..." }) : /* @__PURE__ */ jsxs("div", { className: "min-h-full flex items-center justify-center p-4", children: [
|
|
585
|
+
/* @__PURE__ */ jsx("style", { children: TEXT_LAYER_CSS }),
|
|
586
|
+
/* @__PURE__ */ jsxs("div", { className: "relative shadow-lg rounded", children: [
|
|
587
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "block rounded" }),
|
|
588
|
+
/* @__PURE__ */ jsx(
|
|
589
|
+
"div",
|
|
590
|
+
{
|
|
591
|
+
ref: textLayerRef,
|
|
592
|
+
className: "preview-pdf-textlayer",
|
|
593
|
+
onPointerDown: (e) => e.currentTarget.classList.add("selecting")
|
|
594
|
+
}
|
|
595
|
+
)
|
|
596
|
+
] })
|
|
597
|
+
] })
|
|
504
598
|
}
|
|
505
599
|
)
|
|
506
600
|
] });
|
|
@@ -510,6 +604,61 @@ var DEFAULT_DXF_FONTS = [
|
|
|
510
604
|
"https://cdn.jsdelivr.net/gh/vagran/dxf-viewer-example-src@master/src/assets/fonts/NotoSansDisplay-SemiCondensedLightItalic.ttf",
|
|
511
605
|
"https://cdn.jsdelivr.net/gh/vagran/dxf-viewer-example-src@master/src/assets/fonts/NanumGothic-Regular.ttf"
|
|
512
606
|
];
|
|
607
|
+
var DXF_EDIT_COMMANDS = {
|
|
608
|
+
l: "LINE",
|
|
609
|
+
line: "LINE",
|
|
610
|
+
pl: "PLINE",
|
|
611
|
+
pline: "PLINE",
|
|
612
|
+
ex: "EXTEND",
|
|
613
|
+
extend: "EXTEND",
|
|
614
|
+
tr: "TRIM",
|
|
615
|
+
trim: "TRIM",
|
|
616
|
+
e: "ERASE",
|
|
617
|
+
erase: "ERASE",
|
|
618
|
+
m: "MOVE",
|
|
619
|
+
move: "MOVE",
|
|
620
|
+
co: "COPY",
|
|
621
|
+
cp: "COPY",
|
|
622
|
+
copy: "COPY",
|
|
623
|
+
o: "OFFSET",
|
|
624
|
+
offset: "OFFSET",
|
|
625
|
+
f: "FILLET",
|
|
626
|
+
fillet: "FILLET",
|
|
627
|
+
cha: "CHAMFER",
|
|
628
|
+
chamfer: "CHAMFER",
|
|
629
|
+
x: "EXPLODE",
|
|
630
|
+
explode: "EXPLODE",
|
|
631
|
+
mi: "MIRROR",
|
|
632
|
+
mirror: "MIRROR",
|
|
633
|
+
ro: "ROTATE",
|
|
634
|
+
rotate: "ROTATE",
|
|
635
|
+
sc: "SCALE",
|
|
636
|
+
scale: "SCALE",
|
|
637
|
+
s: "STRETCH",
|
|
638
|
+
stretch: "STRETCH",
|
|
639
|
+
ar: "ARRAY",
|
|
640
|
+
array: "ARRAY",
|
|
641
|
+
rec: "RECTANG",
|
|
642
|
+
rectang: "RECTANG",
|
|
643
|
+
rectangle: "RECTANG",
|
|
644
|
+
c: "CIRCLE",
|
|
645
|
+
circle: "CIRCLE",
|
|
646
|
+
a: "ARC",
|
|
647
|
+
arc: "ARC",
|
|
648
|
+
el: "ELLIPSE",
|
|
649
|
+
ellipse: "ELLIPSE",
|
|
650
|
+
t: "MTEXT",
|
|
651
|
+
mt: "MTEXT",
|
|
652
|
+
mtext: "MTEXT",
|
|
653
|
+
text: "TEXT",
|
|
654
|
+
b: "BLOCK",
|
|
655
|
+
block: "BLOCK",
|
|
656
|
+
i: "INSERT",
|
|
657
|
+
insert: "INSERT",
|
|
658
|
+
ha: "HATCH",
|
|
659
|
+
hatch: "HATCH"
|
|
660
|
+
};
|
|
661
|
+
var DXF_CMD_HELP = "Commands: DI distance \xB7 DIM/DLI linear dim \xB7 H / V force axis \xB7 <number> lock \u0394 \xB7 U undo pick \xB7 Z fit \xB7 LA layers \xB7 Esc exit";
|
|
513
662
|
function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
514
663
|
const containerRef = useRef(null);
|
|
515
664
|
const viewerRef = useRef(null);
|
|
@@ -519,8 +668,9 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
519
668
|
const [showLayers, setShowLayers] = useState(false);
|
|
520
669
|
const [showHint, setShowHint] = useState(true);
|
|
521
670
|
const [measureEnabled, setMeasureEnabled] = useState(false);
|
|
522
|
-
const [measureMode, setMeasureMode] = useState("
|
|
671
|
+
const [measureMode, setMeasureMode] = useState("auto");
|
|
523
672
|
const [measureDistance, setMeasureDistance] = useState(null);
|
|
673
|
+
const [measureResolved, setMeasureResolved] = useState(null);
|
|
524
674
|
const [measureFixedDist, setMeasureFixedDist] = useState(null);
|
|
525
675
|
const [measureFixedInput, setMeasureFixedInput] = useState("");
|
|
526
676
|
const measureModeRef = useRef(measureMode);
|
|
@@ -532,6 +682,13 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
532
682
|
measureFixedDistRef.current = measureFixedDist;
|
|
533
683
|
}, [measureFixedDist]);
|
|
534
684
|
const measureRedrawRef = useRef(null);
|
|
685
|
+
const measureResetRef = useRef(null);
|
|
686
|
+
const measureUndoRef = useRef(null);
|
|
687
|
+
const [cmdValue, setCmdValue] = useState("");
|
|
688
|
+
const [cmdEcho, setCmdEcho] = useState(null);
|
|
689
|
+
const lastCmdRef = useRef("");
|
|
690
|
+
const cmdInputRef = useRef(null);
|
|
691
|
+
const rootRef = useRef(null);
|
|
535
692
|
const measureRef = useRef(null);
|
|
536
693
|
useEffect(() => {
|
|
537
694
|
let cancelled = false;
|
|
@@ -635,6 +792,7 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
635
792
|
const t = setTimeout(() => setShowHint(false), 5e3);
|
|
636
793
|
return () => clearTimeout(t);
|
|
637
794
|
}, [showHint, loading]);
|
|
795
|
+
const layersKey = layers.map((l) => l.visible ? "1" : "0").join("");
|
|
638
796
|
useEffect(() => {
|
|
639
797
|
const v = viewerRef.current;
|
|
640
798
|
if (loading || error || !v) return;
|
|
@@ -651,6 +809,7 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
651
809
|
if (!measureEnabled) {
|
|
652
810
|
teardown();
|
|
653
811
|
setMeasureDistance(null);
|
|
812
|
+
setMeasureResolved(null);
|
|
654
813
|
return;
|
|
655
814
|
}
|
|
656
815
|
const overlay = document.createElement("div");
|
|
@@ -674,13 +833,18 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
674
833
|
defs.appendChild(marker);
|
|
675
834
|
svg.appendChild(defs);
|
|
676
835
|
overlay.appendChild(svg);
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
836
|
+
const mkRefLine = () => {
|
|
837
|
+
const el = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
838
|
+
el.setAttribute("stroke", "#ff8800");
|
|
839
|
+
el.setAttribute("stroke-width", "1");
|
|
840
|
+
el.setAttribute("stroke-dasharray", "6,4");
|
|
841
|
+
el.setAttribute("opacity", "0.55");
|
|
842
|
+
el.style.display = "none";
|
|
843
|
+
svg.appendChild(el);
|
|
844
|
+
return el;
|
|
845
|
+
};
|
|
846
|
+
const refLineEl = mkRefLine();
|
|
847
|
+
const refLineVEl = mkRefLine();
|
|
684
848
|
const extLineA = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
685
849
|
extLineA.setAttribute("stroke", "#ff8800");
|
|
686
850
|
extLineA.setAttribute("stroke-width", "1");
|
|
@@ -756,10 +920,44 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
756
920
|
poly.setAttribute("stroke-linejoin", "round");
|
|
757
921
|
g.appendChild(poly);
|
|
758
922
|
});
|
|
923
|
+
const snapGlyphMidpoint = mkSnapGlyph((g) => {
|
|
924
|
+
const poly = document.createElementNS(SVGNS, "polygon");
|
|
925
|
+
poly.setAttribute("points", "11,3 19,18 3,18");
|
|
926
|
+
poly.setAttribute("fill", "rgba(255,255,255,0.9)");
|
|
927
|
+
poly.setAttribute("stroke", "#ff8800");
|
|
928
|
+
poly.setAttribute("stroke-width", "1.8");
|
|
929
|
+
poly.setAttribute("stroke-linejoin", "round");
|
|
930
|
+
g.appendChild(poly);
|
|
931
|
+
});
|
|
932
|
+
const snapGlyphNode = mkSnapGlyph((g) => {
|
|
933
|
+
const c = document.createElementNS(SVGNS, "circle");
|
|
934
|
+
c.setAttribute("cx", "11");
|
|
935
|
+
c.setAttribute("cy", "11");
|
|
936
|
+
c.setAttribute("r", "7");
|
|
937
|
+
c.setAttribute("fill", "rgba(255,255,255,0.9)");
|
|
938
|
+
c.setAttribute("stroke", "#ff8800");
|
|
939
|
+
c.setAttribute("stroke-width", "1.8");
|
|
940
|
+
g.appendChild(c);
|
|
941
|
+
const mkLn = (x1, y1, x2, y2) => {
|
|
942
|
+
const ln = document.createElementNS(SVGNS, "line");
|
|
943
|
+
ln.setAttribute("x1", String(x1));
|
|
944
|
+
ln.setAttribute("y1", String(y1));
|
|
945
|
+
ln.setAttribute("x2", String(x2));
|
|
946
|
+
ln.setAttribute("y2", String(y2));
|
|
947
|
+
ln.setAttribute("stroke", "#ff8800");
|
|
948
|
+
ln.setAttribute("stroke-width", "1.6");
|
|
949
|
+
ln.setAttribute("stroke-linecap", "round");
|
|
950
|
+
return ln;
|
|
951
|
+
};
|
|
952
|
+
g.appendChild(mkLn(6.5, 6.5, 15.5, 15.5));
|
|
953
|
+
g.appendChild(mkLn(15.5, 6.5, 6.5, 15.5));
|
|
954
|
+
});
|
|
759
955
|
const setSnapGlyph = (type) => {
|
|
760
956
|
snapGlyphEndpoint.style.display = type === "endpoint" ? "" : "none";
|
|
761
957
|
snapGlyphIntersection.style.display = type === "intersection" ? "" : "none";
|
|
762
958
|
snapGlyphLine.style.display = type === "line" ? "" : "none";
|
|
959
|
+
snapGlyphMidpoint.style.display = type === "midpoint" ? "" : "none";
|
|
960
|
+
snapGlyphNode.style.display = type === "node" ? "" : "none";
|
|
763
961
|
};
|
|
764
962
|
overlay.appendChild(snapEl);
|
|
765
963
|
measureRef.current = {
|
|
@@ -771,12 +969,14 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
771
969
|
fixedLine: fixedLineEl,
|
|
772
970
|
fixedLabel: null,
|
|
773
971
|
refLine: refLineEl,
|
|
972
|
+
refLineV: refLineVEl,
|
|
774
973
|
extLineA,
|
|
775
974
|
extLineB,
|
|
776
975
|
markers: [],
|
|
777
976
|
label: null,
|
|
778
977
|
snap: snapEl,
|
|
779
|
-
|
|
978
|
+
segs: null,
|
|
979
|
+
nodes: null
|
|
780
980
|
};
|
|
781
981
|
let THREE = null;
|
|
782
982
|
let ready = false;
|
|
@@ -786,28 +986,82 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
786
986
|
const w = canvas.clientWidth, h = canvas.clientHeight;
|
|
787
987
|
return { x: (v3.x + 1) / 2 * w, y: (-v3.y + 1) / 2 * h };
|
|
788
988
|
};
|
|
989
|
+
const MAX_SNAP_SEGS = 4e5;
|
|
789
990
|
(async () => {
|
|
790
991
|
try {
|
|
791
992
|
THREE = await import(
|
|
792
993
|
/* @vite-ignore */
|
|
793
994
|
'three'
|
|
794
995
|
);
|
|
795
|
-
const
|
|
796
|
-
if (!
|
|
797
|
-
const
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
996
|
+
const st = measureRef.current;
|
|
997
|
+
if (!st) return;
|
|
998
|
+
const segXY = [];
|
|
999
|
+
const nodeXY = [];
|
|
1000
|
+
let truncated = false;
|
|
1001
|
+
const instanceXforms = (g) => {
|
|
1002
|
+
const t0 = g?.attributes?.instanceTransform0;
|
|
1003
|
+
const t1 = g?.attributes?.instanceTransform1;
|
|
1004
|
+
if (t0 && t1) {
|
|
1005
|
+
const out = [];
|
|
1006
|
+
const n = Math.min(t0.count, t1.count);
|
|
1007
|
+
for (let k = 0; k < n; k++) {
|
|
1008
|
+
out.push([t0.getX(k), t0.getY(k), t0.getZ(k), t1.getX(k), t1.getY(k), t1.getZ(k)]);
|
|
1009
|
+
}
|
|
1010
|
+
return out;
|
|
1011
|
+
}
|
|
1012
|
+
const tp = g?.attributes?.instanceTransform;
|
|
1013
|
+
if (tp) {
|
|
1014
|
+
const out = [];
|
|
1015
|
+
for (let k = 0; k < tp.count; k++) out.push([1, 0, tp.getX(k), 0, 1, tp.getY(k)]);
|
|
1016
|
+
return out;
|
|
1017
|
+
}
|
|
1018
|
+
return [[1, 0, 0, 0, 1, 0]];
|
|
1019
|
+
};
|
|
1020
|
+
const visit = (obj) => {
|
|
1021
|
+
const isSeg = !!obj?.isLineSegments;
|
|
1022
|
+
const isPts = !!obj?.isPoints;
|
|
1023
|
+
if (!isSeg && !isPts) return;
|
|
1024
|
+
const g = obj.geometry;
|
|
1025
|
+
const pos = g?.attributes?.position;
|
|
801
1026
|
if (!pos) return;
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
1027
|
+
const xfs = instanceXforms(g);
|
|
1028
|
+
if (isSeg) {
|
|
1029
|
+
const idx = g.index;
|
|
1030
|
+
const pairCount = Math.floor((idx ? idx.count : pos.count) / 2);
|
|
1031
|
+
for (let p = 0; p < pairCount; p++) {
|
|
1032
|
+
const ia = idx ? idx.getX(2 * p) : 2 * p;
|
|
1033
|
+
const ib = idx ? idx.getX(2 * p + 1) : 2 * p + 1;
|
|
1034
|
+
const ax = pos.getX(ia), ay = pos.getY(ia);
|
|
1035
|
+
const bx = pos.getX(ib), by = pos.getY(ib);
|
|
1036
|
+
if (!Number.isFinite(ax + ay + bx + by)) continue;
|
|
1037
|
+
for (const m of xfs) {
|
|
1038
|
+
if (segXY.length >= MAX_SNAP_SEGS * 4) {
|
|
1039
|
+
truncated = true;
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
const tax = m[0] * ax + m[1] * ay + m[2], tay = m[3] * ax + m[4] * ay + m[5];
|
|
1043
|
+
const tbx = m[0] * bx + m[1] * by + m[2], tby = m[3] * bx + m[4] * by + m[5];
|
|
1044
|
+
if (tax === tbx && tay === tby) continue;
|
|
1045
|
+
segXY.push(tax, tay, tbx, tby);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
} else {
|
|
1049
|
+
for (let i = 0; i < pos.count; i++) {
|
|
1050
|
+
const x = pos.getX(i), y = pos.getY(i);
|
|
1051
|
+
if (!Number.isFinite(x + y)) continue;
|
|
1052
|
+
for (const m of xfs) {
|
|
1053
|
+
nodeXY.push(m[0] * x + m[1] * y + m[2], m[3] * x + m[4] * y + m[5]);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
809
1056
|
}
|
|
810
|
-
}
|
|
1057
|
+
};
|
|
1058
|
+
if (typeof scene.traverseVisible === "function") scene.traverseVisible(visit);
|
|
1059
|
+
else scene.traverse(visit);
|
|
1060
|
+
st.segs = new Float64Array(segXY);
|
|
1061
|
+
st.nodes = new Float64Array(nodeXY);
|
|
1062
|
+
if (truncated) {
|
|
1063
|
+
console.warn(`[Preview] DXF snap cache truncated at ${MAX_SNAP_SEGS} segments \u2014 snapping may miss some geometry.`);
|
|
1064
|
+
}
|
|
811
1065
|
ready = true;
|
|
812
1066
|
} catch {
|
|
813
1067
|
}
|
|
@@ -824,54 +1078,92 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
824
1078
|
};
|
|
825
1079
|
const findSnap = (cx, cy) => {
|
|
826
1080
|
const s = measureRef.current;
|
|
827
|
-
if (!s || !ready) return null;
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
const
|
|
1081
|
+
if (!s || !ready || !s.segs) return null;
|
|
1082
|
+
const o = pxFromScene(0, 0);
|
|
1083
|
+
const ex = pxFromScene(1, 0);
|
|
1084
|
+
const ey = pxFromScene(0, 1);
|
|
1085
|
+
const mxx = ex.x - o.x, mxy = ex.y - o.y;
|
|
1086
|
+
const myx = ey.x - o.x, myy = ey.y - o.y;
|
|
1087
|
+
const det = mxx * myy - myx * mxy;
|
|
1088
|
+
if (!det) return null;
|
|
1089
|
+
const csx = ((cx - o.x) * myy - (cy - o.y) * myx) / det;
|
|
1090
|
+
const csy = ((cy - o.y) * mxx - (cx - o.x) * mxy) / det;
|
|
1091
|
+
const rx = SNAP_PX / (Math.hypot(mxx, mxy) || 1);
|
|
1092
|
+
const ry = SNAP_PX / (Math.hypot(myx, myy) || 1);
|
|
1093
|
+
const minX = csx - rx, maxX = csx + rx, minY = csy - ry, maxY = csy + ry;
|
|
1094
|
+
const T2 = SNAP_PX * SNAP_PX;
|
|
1095
|
+
let bestPt = null, dPt = T2;
|
|
1096
|
+
let bestMid = null, dMid = T2;
|
|
1097
|
+
let bestLine = null, dLine = T2;
|
|
1098
|
+
let bestX = null, dX = T2;
|
|
831
1099
|
const cand = [];
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
const
|
|
835
|
-
|
|
836
|
-
const
|
|
837
|
-
const
|
|
838
|
-
|
|
839
|
-
const ldx = seg.bx - seg.ax, ldy = seg.by - seg.ay;
|
|
840
|
-
const llen = Math.sqrt(ldx * ldx + ldy * ldy) || 1;
|
|
841
|
-
const segDir = { dx: ldx / llen, dy: ldy / llen };
|
|
1100
|
+
const segs = s.segs;
|
|
1101
|
+
for (let i = 0; i < segs.length; i += 4) {
|
|
1102
|
+
const ax = segs[i], ay = segs[i + 1], bx = segs[i + 2], by = segs[i + 3];
|
|
1103
|
+
if (ax < minX && bx < minX || ax > maxX && bx > maxX || ay < minY && by < minY || ay > maxY && by > maxY) continue;
|
|
1104
|
+
const apx = o.x + mxx * ax + myx * ay, apy = o.y + mxy * ax + myy * ay;
|
|
1105
|
+
const bpx = o.x + mxx * bx + myx * by, bpy = o.y + mxy * bx + myy * by;
|
|
1106
|
+
let near = false;
|
|
842
1107
|
let dx = cx - apx, dy = cy - apy;
|
|
843
|
-
|
|
844
|
-
if (
|
|
845
|
-
|
|
846
|
-
|
|
1108
|
+
let d2 = dx * dx + dy * dy;
|
|
1109
|
+
if (d2 < T2) {
|
|
1110
|
+
near = true;
|
|
1111
|
+
if (d2 < dPt) {
|
|
1112
|
+
dPt = d2;
|
|
1113
|
+
bestPt = { sx: ax, sy: ay, type: "endpoint" };
|
|
1114
|
+
}
|
|
847
1115
|
}
|
|
848
1116
|
dx = cx - bpx;
|
|
849
1117
|
dy = cy - bpy;
|
|
850
|
-
|
|
851
|
-
if (
|
|
852
|
-
|
|
853
|
-
|
|
1118
|
+
d2 = dx * dx + dy * dy;
|
|
1119
|
+
if (d2 < T2) {
|
|
1120
|
+
near = true;
|
|
1121
|
+
if (d2 < dPt) {
|
|
1122
|
+
dPt = d2;
|
|
1123
|
+
bestPt = { sx: bx, sy: by, type: "endpoint" };
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
dx = cx - (apx + bpx) / 2;
|
|
1127
|
+
dy = cy - (apy + bpy) / 2;
|
|
1128
|
+
d2 = dx * dx + dy * dy;
|
|
1129
|
+
if (d2 < T2) {
|
|
1130
|
+
near = true;
|
|
1131
|
+
if (d2 < dMid) {
|
|
1132
|
+
dMid = d2;
|
|
1133
|
+
bestMid = { sx: (ax + bx) / 2, sy: (ay + by) / 2, type: "midpoint" };
|
|
1134
|
+
}
|
|
854
1135
|
}
|
|
855
1136
|
const sdx = bpx - apx, sdy = bpy - apy;
|
|
856
1137
|
const len2 = sdx * sdx + sdy * sdy;
|
|
857
|
-
let dLine2 = Infinity;
|
|
858
1138
|
if (len2 > 0) {
|
|
859
1139
|
const t = ((cx - apx) * sdx + (cy - apy) * sdy) / len2;
|
|
860
1140
|
if (t > 0 && t < 1) {
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1141
|
+
dx = cx - (apx + t * sdx);
|
|
1142
|
+
dy = cy - (apy + t * sdy);
|
|
1143
|
+
d2 = dx * dx + dy * dy;
|
|
1144
|
+
if (d2 < T2) {
|
|
1145
|
+
near = true;
|
|
1146
|
+
if (d2 < dLine) {
|
|
1147
|
+
dLine = d2;
|
|
1148
|
+
bestLine = { sx: ax + t * (bx - ax), sy: ay + t * (by - ay), type: "line" };
|
|
1149
|
+
}
|
|
870
1150
|
}
|
|
871
1151
|
}
|
|
872
1152
|
}
|
|
873
|
-
if (
|
|
874
|
-
|
|
1153
|
+
if (near) cand.push({ ax, ay, bx, by, apx, apy, bpx, bpy });
|
|
1154
|
+
}
|
|
1155
|
+
const nodes = s.nodes;
|
|
1156
|
+
if (nodes) {
|
|
1157
|
+
for (let i = 0; i < nodes.length; i += 2) {
|
|
1158
|
+
const x = nodes[i], y = nodes[i + 1];
|
|
1159
|
+
if (x < minX || x > maxX || y < minY || y > maxY) continue;
|
|
1160
|
+
const dx = cx - (o.x + mxx * x + myx * y);
|
|
1161
|
+
const dy = cy - (o.y + mxy * x + myy * y);
|
|
1162
|
+
const d2 = dx * dx + dy * dy;
|
|
1163
|
+
if (d2 < dPt) {
|
|
1164
|
+
dPt = d2;
|
|
1165
|
+
bestPt = { sx: x, sy: y, type: "node" };
|
|
1166
|
+
}
|
|
875
1167
|
}
|
|
876
1168
|
}
|
|
877
1169
|
for (let i = 0; i < cand.length; i++) {
|
|
@@ -882,16 +1174,13 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
882
1174
|
if (!ix) continue;
|
|
883
1175
|
const dx = cx - ix.px, dy = cy - ix.py;
|
|
884
1176
|
const d2 = dx * dx + dy * dy;
|
|
885
|
-
if (d2 >=
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
const sy = A.seg.ay + ix.t * (A.seg.by - A.seg.ay);
|
|
889
|
-
best = { sx, sy, type: "intersection" };
|
|
890
|
-
bestD2 = d2;
|
|
891
|
-
}
|
|
1177
|
+
if (d2 >= T2 || d2 >= dX) continue;
|
|
1178
|
+
dX = d2;
|
|
1179
|
+
bestX = { sx: A.ax + ix.t * (A.bx - A.ax), sy: A.ay + ix.t * (A.by - A.ay), type: "intersection" };
|
|
892
1180
|
}
|
|
893
1181
|
}
|
|
894
|
-
|
|
1182
|
+
const top = bestX && bestPt ? dX < dPt - 1 ? bestX : bestPt : bestX ?? bestPt;
|
|
1183
|
+
return top ?? bestMid ?? bestLine;
|
|
895
1184
|
};
|
|
896
1185
|
const makeMarker = () => {
|
|
897
1186
|
const el = document.createElement("div");
|
|
@@ -932,16 +1221,23 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
932
1221
|
s.picks[1] = { x: raw.x, y: raw.y };
|
|
933
1222
|
}
|
|
934
1223
|
};
|
|
1224
|
+
const resolveMode = (a, b) => {
|
|
1225
|
+
const mode = measureModeRef.current;
|
|
1226
|
+
if (mode !== "auto") return mode;
|
|
1227
|
+
if (!a || !b) return "horizontal";
|
|
1228
|
+
return Math.abs(b.x - a.x) >= Math.abs(b.y - a.y) ? "horizontal" : "vertical";
|
|
1229
|
+
};
|
|
935
1230
|
const computeMainDimEnds = () => {
|
|
936
1231
|
const s = measureRef.current;
|
|
937
1232
|
const a = s.picks[0];
|
|
938
1233
|
const b = s.picks[1];
|
|
939
|
-
const mode =
|
|
1234
|
+
const mode = resolveMode(a, b);
|
|
1235
|
+
const rawMode = measureModeRef.current;
|
|
940
1236
|
const fixed = measureFixedDistRef.current;
|
|
941
|
-
if (fixed !== null && Number.isFinite(fixed) &&
|
|
1237
|
+
if (fixed !== null && Number.isFinite(fixed) && rawMode === "horizontal") {
|
|
942
1238
|
return { from: { x: b.x, y: a.y }, to: { x: b.x, y: b.y } };
|
|
943
1239
|
}
|
|
944
|
-
if (fixed !== null && Number.isFinite(fixed) &&
|
|
1240
|
+
if (fixed !== null && Number.isFinite(fixed) && rawMode === "vertical") {
|
|
945
1241
|
return { from: { x: a.x, y: b.y }, to: { x: b.x, y: b.y } };
|
|
946
1242
|
}
|
|
947
1243
|
if (mode === "horizontal") return { from: a, to: { x: b.x, y: a.y } };
|
|
@@ -952,36 +1248,49 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
952
1248
|
const s = measureRef.current;
|
|
953
1249
|
if (!s) return;
|
|
954
1250
|
reconcileLockedPick();
|
|
955
|
-
const
|
|
1251
|
+
const rawMode = measureModeRef.current;
|
|
956
1252
|
const fixed = measureFixedDistRef.current;
|
|
957
|
-
const fixedActive = fixed !== null && Number.isFinite(fixed) && (
|
|
1253
|
+
const fixedActive = fixed !== null && Number.isFinite(fixed) && (rawMode === "horizontal" || rawMode === "vertical");
|
|
958
1254
|
if (s.markers[0]) positionMarker(s.markers[0], s.picks[0].x, s.picks[0].y);
|
|
959
1255
|
if (s.markers[1]) positionMarker(s.markers[1], s.picks[1].x, s.picks[1].y);
|
|
960
|
-
const
|
|
961
|
-
|
|
1256
|
+
const drawRefLine = (el, dir, visible) => {
|
|
1257
|
+
if (!el) return;
|
|
1258
|
+
if (!visible || s.picks.length < 1) {
|
|
1259
|
+
el.style.display = "none";
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
962
1262
|
const a = s.picks[0];
|
|
963
1263
|
const w = canvas.clientWidth, h = canvas.clientHeight;
|
|
964
1264
|
const screenSpan = Math.hypot(w, h) * 4;
|
|
965
1265
|
const ap = pxFromScene(a.x, a.y);
|
|
966
|
-
const probe = pxFromScene(a.x +
|
|
1266
|
+
const probe = pxFromScene(a.x + dir.dx, a.y + dir.dy);
|
|
967
1267
|
const pxLen = Math.hypot(probe.x - ap.x, probe.y - ap.y) || 1;
|
|
968
1268
|
const sceneStep = screenSpan / pxLen;
|
|
969
|
-
const
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1269
|
+
const p0 = pxFromScene(a.x - dir.dx * sceneStep, a.y - dir.dy * sceneStep);
|
|
1270
|
+
const p1 = pxFromScene(a.x + dir.dx * sceneStep, a.y + dir.dy * sceneStep);
|
|
1271
|
+
el.setAttribute("x1", String(p0.x));
|
|
1272
|
+
el.setAttribute("y1", String(p0.y));
|
|
1273
|
+
el.setAttribute("x2", String(p1.x));
|
|
1274
|
+
el.setAttribute("y2", String(p1.y));
|
|
1275
|
+
el.style.display = "";
|
|
1276
|
+
};
|
|
1277
|
+
let showH = rawMode === "horizontal";
|
|
1278
|
+
let showV = rawMode === "vertical";
|
|
1279
|
+
if (rawMode === "auto") {
|
|
1280
|
+
if (s.picks.length >= 2) {
|
|
1281
|
+
const r = resolveMode(s.picks[0], s.picks[1]);
|
|
1282
|
+
showH = r === "horizontal";
|
|
1283
|
+
showV = r === "vertical";
|
|
1284
|
+
} else {
|
|
1285
|
+
showH = true;
|
|
1286
|
+
showV = true;
|
|
1287
|
+
}
|
|
982
1288
|
}
|
|
1289
|
+
drawRefLine(s.refLine, { dx: 1, dy: 0 }, showH);
|
|
1290
|
+
drawRefLine(s.refLineV, { dx: 0, dy: 1 }, showV);
|
|
983
1291
|
if (s.picks.length === 2) {
|
|
984
1292
|
const a = s.picks[0], b = s.picks[1];
|
|
1293
|
+
const mode = resolveMode(a, b);
|
|
985
1294
|
const ends = computeMainDimEnds();
|
|
986
1295
|
const fp = pxFromScene(ends.from.x, ends.from.y);
|
|
987
1296
|
const tp = pxFromScene(ends.to.x, ends.to.y);
|
|
@@ -1118,28 +1427,46 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
1118
1427
|
if (!s || s.picks.length !== 2) return;
|
|
1119
1428
|
reconcileLockedPick();
|
|
1120
1429
|
const a = s.picks[0], b = s.picks[1];
|
|
1121
|
-
const
|
|
1430
|
+
const rawMode = measureModeRef.current;
|
|
1431
|
+
const mode = resolveMode(a, b);
|
|
1122
1432
|
const fixed = measureFixedDistRef.current;
|
|
1123
|
-
const fixedActive = fixed !== null && Number.isFinite(fixed) && (
|
|
1433
|
+
const fixedActive = fixed !== null && Number.isFinite(fixed) && (rawMode === "horizontal" || rawMode === "vertical");
|
|
1124
1434
|
let dist;
|
|
1125
1435
|
let suffix = "";
|
|
1126
|
-
|
|
1127
|
-
|
|
1436
|
+
let echo;
|
|
1437
|
+
let shown = mode;
|
|
1438
|
+
const adx = Math.abs(b.x - a.x), ady = Math.abs(b.y - a.y);
|
|
1439
|
+
if (fixedActive && rawMode === "horizontal") {
|
|
1440
|
+
dist = ady;
|
|
1128
1441
|
suffix = " \u2195";
|
|
1129
|
-
|
|
1130
|
-
|
|
1442
|
+
shown = "vertical";
|
|
1443
|
+
echo = `\u0394Y = ${formatMeasureDistance(ady)} with \u0394X locked to ${formatMeasureDistance(Math.abs(fixed))}`;
|
|
1444
|
+
} else if (fixedActive && rawMode === "vertical") {
|
|
1445
|
+
dist = adx;
|
|
1131
1446
|
suffix = " \u2194";
|
|
1447
|
+
shown = "horizontal";
|
|
1448
|
+
echo = `\u0394X = ${formatMeasureDistance(adx)} with \u0394Y locked to ${formatMeasureDistance(Math.abs(fixed))}`;
|
|
1132
1449
|
} else if (mode === "horizontal") {
|
|
1133
|
-
dist =
|
|
1450
|
+
dist = adx;
|
|
1134
1451
|
suffix = " \u2194";
|
|
1452
|
+
echo = `Linear dimension = ${formatMeasureDistance(adx)} (\u0394X)`;
|
|
1135
1453
|
} else if (mode === "vertical") {
|
|
1136
|
-
dist =
|
|
1454
|
+
dist = ady;
|
|
1137
1455
|
suffix = " \u2195";
|
|
1456
|
+
echo = `Linear dimension = ${formatMeasureDistance(ady)} (\u0394Y)`;
|
|
1138
1457
|
} else {
|
|
1139
|
-
|
|
1140
|
-
|
|
1458
|
+
dist = Math.hypot(b.x - a.x, b.y - a.y);
|
|
1459
|
+
echo = `Distance = ${formatMeasureDistance(dist)} \u0394X = ${formatMeasureDistance(adx)} \u0394Y = ${formatMeasureDistance(ady)}`;
|
|
1460
|
+
}
|
|
1461
|
+
if (!Number.isFinite(dist)) {
|
|
1462
|
+
setMeasureDistance(null);
|
|
1463
|
+
setMeasureResolved(null);
|
|
1464
|
+
if (s.label) s.label.style.opacity = "0";
|
|
1465
|
+
return;
|
|
1141
1466
|
}
|
|
1142
1467
|
setMeasureDistance(dist);
|
|
1468
|
+
setMeasureResolved(shown);
|
|
1469
|
+
setCmdEcho(echo);
|
|
1143
1470
|
const label = ensureLabel();
|
|
1144
1471
|
label.style.opacity = "1";
|
|
1145
1472
|
label.textContent = `${formatMeasureDistance(dist)}${suffix}`;
|
|
@@ -1148,23 +1475,42 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
1148
1475
|
recomputeLabel();
|
|
1149
1476
|
updateOverlay();
|
|
1150
1477
|
};
|
|
1478
|
+
const hideDimVisuals = (s) => {
|
|
1479
|
+
s.line.style.display = "none";
|
|
1480
|
+
if (s.fixedLine) s.fixedLine.style.display = "none";
|
|
1481
|
+
if (s.fixedLabel) s.fixedLabel.style.display = "none";
|
|
1482
|
+
if (s.extLineA) s.extLineA.style.display = "none";
|
|
1483
|
+
if (s.extLineB) s.extLineB.style.display = "none";
|
|
1484
|
+
if (s.label) s.label.style.opacity = "0";
|
|
1485
|
+
setMeasureDistance(null);
|
|
1486
|
+
setMeasureResolved(null);
|
|
1487
|
+
};
|
|
1488
|
+
const resetPicks = () => {
|
|
1489
|
+
const s = measureRef.current;
|
|
1490
|
+
if (!s) return;
|
|
1491
|
+
for (const m of s.markers) m.parentElement?.removeChild(m);
|
|
1492
|
+
s.markers = [];
|
|
1493
|
+
s.picks = [];
|
|
1494
|
+
s.rawSecondClick = null;
|
|
1495
|
+
if (s.refLine) s.refLine.style.display = "none";
|
|
1496
|
+
if (s.refLineV) s.refLineV.style.display = "none";
|
|
1497
|
+
hideDimVisuals(s);
|
|
1498
|
+
};
|
|
1499
|
+
measureResetRef.current = resetPicks;
|
|
1500
|
+
measureUndoRef.current = () => {
|
|
1501
|
+
const s = measureRef.current;
|
|
1502
|
+
if (!s || s.picks.length === 0) return;
|
|
1503
|
+
s.picks.pop();
|
|
1504
|
+
const m = s.markers.pop();
|
|
1505
|
+
m?.parentElement?.removeChild(m);
|
|
1506
|
+
s.rawSecondClick = null;
|
|
1507
|
+
hideDimVisuals(s);
|
|
1508
|
+
updateOverlay();
|
|
1509
|
+
};
|
|
1151
1510
|
const doPick = (p) => {
|
|
1152
1511
|
const s = measureRef.current;
|
|
1153
1512
|
if (!s) return;
|
|
1154
|
-
if (s.picks.length === 2)
|
|
1155
|
-
for (const m of s.markers) m.parentElement?.removeChild(m);
|
|
1156
|
-
s.markers = [];
|
|
1157
|
-
s.picks = [];
|
|
1158
|
-
s.rawSecondClick = null;
|
|
1159
|
-
s.line.style.display = "none";
|
|
1160
|
-
if (s.fixedLine) s.fixedLine.style.display = "none";
|
|
1161
|
-
if (s.fixedLabel) s.fixedLabel.style.display = "none";
|
|
1162
|
-
if (s.refLine) s.refLine.style.display = "none";
|
|
1163
|
-
if (s.extLineA) s.extLineA.style.display = "none";
|
|
1164
|
-
if (s.extLineB) s.extLineB.style.display = "none";
|
|
1165
|
-
if (s.label) s.label.style.opacity = "0";
|
|
1166
|
-
setMeasureDistance(null);
|
|
1167
|
-
}
|
|
1513
|
+
if (s.picks.length === 2) resetPicks();
|
|
1168
1514
|
if (s.picks.length === 0) {
|
|
1169
1515
|
s.picks.push({ x: p.x, y: p.y });
|
|
1170
1516
|
s.markers.push(makeMarker());
|
|
@@ -1211,10 +1557,13 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
1211
1557
|
canvas.removeEventListener("pointermove", handlePointerMove);
|
|
1212
1558
|
window.removeEventListener("keydown", onKeyDown);
|
|
1213
1559
|
measureRedrawRef.current = null;
|
|
1560
|
+
measureResetRef.current = null;
|
|
1561
|
+
measureUndoRef.current = null;
|
|
1214
1562
|
teardown();
|
|
1215
1563
|
setMeasureDistance(null);
|
|
1564
|
+
setMeasureResolved(null);
|
|
1216
1565
|
};
|
|
1217
|
-
}, [measureEnabled, loading, error]);
|
|
1566
|
+
}, [measureEnabled, loading, error, layersKey]);
|
|
1218
1567
|
useEffect(() => {
|
|
1219
1568
|
measureRedrawRef.current?.();
|
|
1220
1569
|
}, [measureMode, measureFixedDist]);
|
|
@@ -1264,12 +1613,170 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
1264
1613
|
} catch {
|
|
1265
1614
|
}
|
|
1266
1615
|
};
|
|
1616
|
+
const runCommand = (raw) => {
|
|
1617
|
+
const exec = raw.trim() || lastCmdRef.current;
|
|
1618
|
+
setCmdValue("");
|
|
1619
|
+
if (!exec) return;
|
|
1620
|
+
const cmd = exec.toLowerCase().split(/\s+/)[0];
|
|
1621
|
+
const remember = () => {
|
|
1622
|
+
lastCmdRef.current = exec;
|
|
1623
|
+
};
|
|
1624
|
+
const startMeasure = (mode, echo) => {
|
|
1625
|
+
setMeasureEnabled(true);
|
|
1626
|
+
setMeasureMode(mode);
|
|
1627
|
+
measureResetRef.current?.();
|
|
1628
|
+
setCmdEcho(echo);
|
|
1629
|
+
remember();
|
|
1630
|
+
};
|
|
1631
|
+
if (/^-?(\d+\.?\d*|\.\d+)$/.test(cmd)) {
|
|
1632
|
+
if (measureEnabled && (measureMode === "horizontal" || measureMode === "vertical")) {
|
|
1633
|
+
const n = parseFloat(cmd);
|
|
1634
|
+
if (n) {
|
|
1635
|
+
setMeasureFixedInput(cmd);
|
|
1636
|
+
setMeasureFixedDist(n);
|
|
1637
|
+
setCmdEcho(`\u0394${measureMode === "horizontal" ? "X" : "Y"} locked to ${formatMeasureDistance(Math.abs(n))} \u2014 the label shows the perpendicular distance`);
|
|
1638
|
+
} else {
|
|
1639
|
+
setMeasureFixedInput("");
|
|
1640
|
+
setMeasureFixedDist(null);
|
|
1641
|
+
setCmdEcho("Fixed distance cleared.");
|
|
1642
|
+
}
|
|
1643
|
+
} else {
|
|
1644
|
+
setCmdEcho("Fixed distances apply in H or V mode \u2014 type H or V first.");
|
|
1645
|
+
}
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
switch (cmd) {
|
|
1649
|
+
case "di":
|
|
1650
|
+
case "dist":
|
|
1651
|
+
case "mea":
|
|
1652
|
+
case "measuregeom":
|
|
1653
|
+
startMeasure("point", "DIST \u2014 click two points; straight-line distance (Esc to exit)");
|
|
1654
|
+
break;
|
|
1655
|
+
case "dim":
|
|
1656
|
+
case "dli":
|
|
1657
|
+
case "dimlin":
|
|
1658
|
+
case "dimlinear":
|
|
1659
|
+
startMeasure("auto", "DIMLINEAR \u2014 click two points; measures \u0394X or \u0394Y, whichever is larger (H / V to force)");
|
|
1660
|
+
break;
|
|
1661
|
+
// H / V / AUTO switch the axis without dropping existing picks —
|
|
1662
|
+
// same as clicking the pill.
|
|
1663
|
+
case "h":
|
|
1664
|
+
case "hor":
|
|
1665
|
+
case "horizontal":
|
|
1666
|
+
setMeasureEnabled(true);
|
|
1667
|
+
setMeasureMode("horizontal");
|
|
1668
|
+
setCmdEcho("Horizontal \u2014 \u0394X between the two picks");
|
|
1669
|
+
remember();
|
|
1670
|
+
break;
|
|
1671
|
+
case "v":
|
|
1672
|
+
case "ver":
|
|
1673
|
+
case "vertical":
|
|
1674
|
+
setMeasureEnabled(true);
|
|
1675
|
+
setMeasureMode("vertical");
|
|
1676
|
+
setCmdEcho("Vertical \u2014 \u0394Y between the two picks");
|
|
1677
|
+
remember();
|
|
1678
|
+
break;
|
|
1679
|
+
case "au":
|
|
1680
|
+
case "auto":
|
|
1681
|
+
setMeasureEnabled(true);
|
|
1682
|
+
setMeasureMode("auto");
|
|
1683
|
+
setCmdEcho("Auto (DIMLINEAR) \u2014 measures along the dominant axis of the two picks");
|
|
1684
|
+
remember();
|
|
1685
|
+
break;
|
|
1686
|
+
case "measure":
|
|
1687
|
+
setMeasureEnabled(!measureEnabled);
|
|
1688
|
+
setCmdEcho(measureEnabled ? "Measure off." : "Measure on \u2014 click two points.");
|
|
1689
|
+
remember();
|
|
1690
|
+
break;
|
|
1691
|
+
case "u":
|
|
1692
|
+
case "undo":
|
|
1693
|
+
measureUndoRef.current?.();
|
|
1694
|
+
setCmdEcho("Last pick removed.");
|
|
1695
|
+
remember();
|
|
1696
|
+
break;
|
|
1697
|
+
case "z":
|
|
1698
|
+
case "ze":
|
|
1699
|
+
case "zoom":
|
|
1700
|
+
case "fit":
|
|
1701
|
+
case "zoomextents":
|
|
1702
|
+
handleResetView();
|
|
1703
|
+
setCmdEcho("Zoom extents.");
|
|
1704
|
+
remember();
|
|
1705
|
+
break;
|
|
1706
|
+
case "la":
|
|
1707
|
+
case "layer":
|
|
1708
|
+
case "layers":
|
|
1709
|
+
setShowLayers((s) => !s);
|
|
1710
|
+
setCmdEcho("Layer panel toggled.");
|
|
1711
|
+
remember();
|
|
1712
|
+
break;
|
|
1713
|
+
case "off":
|
|
1714
|
+
case "clear":
|
|
1715
|
+
setMeasureFixedDist(null);
|
|
1716
|
+
setMeasureFixedInput("");
|
|
1717
|
+
measureResetRef.current?.();
|
|
1718
|
+
setCmdEcho("Measurement cleared.");
|
|
1719
|
+
remember();
|
|
1720
|
+
break;
|
|
1721
|
+
case "?":
|
|
1722
|
+
case "help":
|
|
1723
|
+
setCmdEcho(DXF_CMD_HELP);
|
|
1724
|
+
break;
|
|
1725
|
+
default: {
|
|
1726
|
+
const editCmd = DXF_EDIT_COMMANDS[cmd];
|
|
1727
|
+
if (editCmd) setCmdEcho(`${editCmd} is a drawing command \u2014 Preview is a read-only viewer. Measuring: DI, DIM, H, V (? for help)`);
|
|
1728
|
+
else setCmdEcho(`Unknown command "${cmd.toUpperCase()}" \u2014 try DI, DIM, H, V, Z, LA (? for help)`);
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
};
|
|
1732
|
+
useEffect(() => {
|
|
1733
|
+
const onKey = (e) => {
|
|
1734
|
+
if (e.defaultPrevented || e.metaKey || e.ctrlKey || e.altKey) return;
|
|
1735
|
+
if (e.key.length !== 1 || e.key === " ") return;
|
|
1736
|
+
const t = e.target;
|
|
1737
|
+
if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) return;
|
|
1738
|
+
const root = rootRef.current;
|
|
1739
|
+
if (!root) return;
|
|
1740
|
+
const myModal = root.closest("[data-modal-id]");
|
|
1741
|
+
if (myModal && getActiveModalId() !== myModal.dataset.modalId) return;
|
|
1742
|
+
cmdInputRef.current?.focus();
|
|
1743
|
+
};
|
|
1744
|
+
window.addEventListener("keydown", onKey);
|
|
1745
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
1746
|
+
}, []);
|
|
1747
|
+
const cmdValueRef = useRef(cmdValue);
|
|
1748
|
+
const measureEnabledRef = useRef(measureEnabled);
|
|
1749
|
+
useEffect(() => {
|
|
1750
|
+
cmdValueRef.current = cmdValue;
|
|
1751
|
+
}, [cmdValue]);
|
|
1752
|
+
useEffect(() => {
|
|
1753
|
+
measureEnabledRef.current = measureEnabled;
|
|
1754
|
+
}, [measureEnabled]);
|
|
1755
|
+
useEffect(() => {
|
|
1756
|
+
return registerModalEscapeInterceptor(() => {
|
|
1757
|
+
const root = rootRef.current;
|
|
1758
|
+
if (!root) return false;
|
|
1759
|
+
const myModal = root.closest("[data-modal-id]");
|
|
1760
|
+
if (!myModal || getActiveModalId() !== myModal.dataset.modalId) return false;
|
|
1761
|
+
if (cmdValueRef.current) {
|
|
1762
|
+
setCmdValue("");
|
|
1763
|
+
setCmdEcho("*Cancel*");
|
|
1764
|
+
return true;
|
|
1765
|
+
}
|
|
1766
|
+
if (measureEnabledRef.current) {
|
|
1767
|
+
setMeasureEnabled(false);
|
|
1768
|
+
setCmdEcho("Measure off.");
|
|
1769
|
+
return true;
|
|
1770
|
+
}
|
|
1771
|
+
return false;
|
|
1772
|
+
});
|
|
1773
|
+
}, []);
|
|
1267
1774
|
const btn = "px-2 py-1 rounded hover:bg-gray-200 transition-colors text-gray-600 flex items-center gap-1";
|
|
1268
1775
|
const colorHex = (n) => {
|
|
1269
1776
|
if (typeof n !== "number") return "#999";
|
|
1270
1777
|
return "#" + n.toString(16).padStart(6, "0");
|
|
1271
1778
|
};
|
|
1272
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
|
|
1779
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: "flex flex-col h-full", children: [
|
|
1273
1780
|
/* @__PURE__ */ jsxs(PanelActions, { children: [
|
|
1274
1781
|
/* @__PURE__ */ jsxs(
|
|
1275
1782
|
"button",
|
|
@@ -1297,7 +1804,7 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
1297
1804
|
{
|
|
1298
1805
|
onClick: () => setMeasureEnabled((m) => !m),
|
|
1299
1806
|
className: btn + (measureEnabled ? " bg-gray-200" : ""),
|
|
1300
|
-
title: measureEnabled ? "Stop measuring (Esc)" : "Measure distance \u2014 click two points on the drawing",
|
|
1807
|
+
title: measureEnabled ? "Stop measuring (Esc)" : "Measure distance \u2014 click two points on the drawing, or type DI / DIM below",
|
|
1301
1808
|
children: [
|
|
1302
1809
|
/* @__PURE__ */ jsxs("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: [
|
|
1303
1810
|
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 14.25l6-6 6 6 4.5-4.5M9.75 8.25v3M12.75 11.25v3M15.75 14.25v3" }),
|
|
@@ -1312,10 +1819,10 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
1312
1819
|
/* @__PURE__ */ jsx(
|
|
1313
1820
|
"button",
|
|
1314
1821
|
{
|
|
1315
|
-
onClick: () => setMeasureMode("
|
|
1316
|
-
className: `px-2 transition-colors ${measureMode === "
|
|
1317
|
-
title: "
|
|
1318
|
-
children: "
|
|
1822
|
+
onClick: () => setMeasureMode("auto"),
|
|
1823
|
+
className: `px-2 transition-colors ${measureMode === "auto" ? "bg-orange-500 text-white" : "bg-white text-gray-600 hover:bg-gray-50"}`,
|
|
1824
|
+
title: "Auto \u2014 AutoCAD DIMLINEAR: measures \u0394X or \u0394Y, whichever is larger between the two picks",
|
|
1825
|
+
children: "Auto"
|
|
1319
1826
|
}
|
|
1320
1827
|
),
|
|
1321
1828
|
/* @__PURE__ */ jsx(
|
|
@@ -1335,6 +1842,15 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
1335
1842
|
title: "Vertical \u2014 distance along the Y axis between two picks (AutoCAD DIMLINEAR vertical)",
|
|
1336
1843
|
children: "V"
|
|
1337
1844
|
}
|
|
1845
|
+
),
|
|
1846
|
+
/* @__PURE__ */ jsx(
|
|
1847
|
+
"button",
|
|
1848
|
+
{
|
|
1849
|
+
onClick: () => setMeasureMode("point"),
|
|
1850
|
+
className: `px-2 transition-colors ${measureMode === "point" ? "bg-orange-500 text-white" : "bg-white text-gray-600 hover:bg-gray-50"}`,
|
|
1851
|
+
title: "Point \u2014 straight-line (Euclidean) distance between two picks (AutoCAD DIST)",
|
|
1852
|
+
children: "Point"
|
|
1853
|
+
}
|
|
1338
1854
|
)
|
|
1339
1855
|
] }),
|
|
1340
1856
|
(measureMode === "horizontal" || measureMode === "vertical") && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
@@ -1377,10 +1893,10 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
1377
1893
|
"div",
|
|
1378
1894
|
{
|
|
1379
1895
|
className: "px-2 py-1 text-[11px] font-mono font-semibold text-orange-600 bg-orange-50 border border-orange-200 rounded whitespace-nowrap",
|
|
1380
|
-
title:
|
|
1896
|
+
title: measureResolved === "horizontal" ? `Horizontal distance (\u0394x) between the two picked points${measureMode === "auto" ? " \u2014 Auto resolved to the X axis" : ""}` : measureResolved === "vertical" ? `Vertical distance (\u0394y) between the two picked points${measureMode === "auto" ? " \u2014 Auto resolved to the Y axis" : ""}` : "Straight-line distance between the two picked points",
|
|
1381
1897
|
children: [
|
|
1382
1898
|
formatMeasureDistance(measureDistance),
|
|
1383
|
-
|
|
1899
|
+
measureResolved === "horizontal" ? " \u2194" : measureResolved === "vertical" ? " \u2195" : ""
|
|
1384
1900
|
]
|
|
1385
1901
|
}
|
|
1386
1902
|
),
|
|
@@ -1436,10 +1952,50 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
|
|
|
1436
1952
|
"Scroll to zoom"
|
|
1437
1953
|
] }),
|
|
1438
1954
|
/* @__PURE__ */ jsx("span", { className: "text-white/40", children: "\u2022" }),
|
|
1439
|
-
/* @__PURE__ */ jsx("span", { children: "Fit to reset" })
|
|
1955
|
+
/* @__PURE__ */ jsx("span", { children: "Fit to reset" }),
|
|
1956
|
+
/* @__PURE__ */ jsx("span", { className: "text-white/40", children: "\u2022" }),
|
|
1957
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1958
|
+
"Type ",
|
|
1959
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono font-semibold", children: "DI" }),
|
|
1960
|
+
" / ",
|
|
1961
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono font-semibold", children: "DIM" }),
|
|
1962
|
+
" to measure"
|
|
1963
|
+
] })
|
|
1440
1964
|
] }),
|
|
1441
1965
|
loading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-white/80 text-sm text-gray-500", children: "Loading drawing\u2026" }),
|
|
1442
1966
|
error && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-sm text-red-600 px-6 text-center", children: error })
|
|
1967
|
+
] }),
|
|
1968
|
+
/* @__PURE__ */ jsxs("div", { className: "shrink-0 border-t border-gray-200 bg-gray-50", children: [
|
|
1969
|
+
cmdEcho && /* @__PURE__ */ jsx("div", { className: "px-2.5 pt-1 text-[11px] font-mono text-gray-500 truncate", title: cmdEcho, children: cmdEcho }),
|
|
1970
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2.5 h-7", children: [
|
|
1971
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-mono font-semibold text-gray-400 select-none", children: ">" }),
|
|
1972
|
+
/* @__PURE__ */ jsx(
|
|
1973
|
+
"input",
|
|
1974
|
+
{
|
|
1975
|
+
ref: cmdInputRef,
|
|
1976
|
+
value: cmdValue,
|
|
1977
|
+
onChange: (e) => setCmdValue(e.target.value),
|
|
1978
|
+
onKeyDown: (e) => {
|
|
1979
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1980
|
+
e.preventDefault();
|
|
1981
|
+
runCommand(cmdValue);
|
|
1982
|
+
} else if (e.key === "Escape") {
|
|
1983
|
+
if (cmdValue) {
|
|
1984
|
+
e.stopPropagation();
|
|
1985
|
+
setCmdValue("");
|
|
1986
|
+
setCmdEcho("*Cancel*");
|
|
1987
|
+
} else {
|
|
1988
|
+
e.target.blur();
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
},
|
|
1992
|
+
placeholder: "Type a command \u2014 DI, DIM, H, V, Z, LA (? for help)",
|
|
1993
|
+
spellCheck: false,
|
|
1994
|
+
autoComplete: "off",
|
|
1995
|
+
className: "flex-1 min-w-0 bg-transparent text-[11px] font-mono text-gray-700 focus:outline-none placeholder:text-gray-300"
|
|
1996
|
+
}
|
|
1997
|
+
)
|
|
1998
|
+
] })
|
|
1443
1999
|
] })
|
|
1444
2000
|
] });
|
|
1445
2001
|
}
|
|
@@ -1463,8 +2019,7 @@ function hexToRgb(OV, hex) {
|
|
|
1463
2019
|
return new OV.RGBColor(n >> 16 & 255, n >> 8 & 255, n & 255);
|
|
1464
2020
|
}
|
|
1465
2021
|
function formatMeasureDistance(mm) {
|
|
1466
|
-
if (mm >= 1e3) return `${(mm / 1e3).toFixed(
|
|
1467
|
-
if (mm >= 10) return `${mm.toFixed(1)} mm`;
|
|
2022
|
+
if (mm >= 1e3) return `${(mm / 1e3).toFixed(3)} m`;
|
|
1468
2023
|
return `${mm.toFixed(2)} mm`;
|
|
1469
2024
|
}
|
|
1470
2025
|
function StepPanel({ url, filename, onDownload, onEmail }) {
|
|
@@ -2744,5 +3299,5 @@ function ImagePanel({ url, filename, onDownload, onEmail }) {
|
|
|
2744
3299
|
}
|
|
2745
3300
|
|
|
2746
3301
|
export { Preview, setPdfPreview };
|
|
2747
|
-
//# sourceMappingURL=chunk-
|
|
2748
|
-
//# sourceMappingURL=chunk-
|
|
3302
|
+
//# sourceMappingURL=chunk-UFTJG6IM.js.map
|
|
3303
|
+
//# sourceMappingURL=chunk-UFTJG6IM.js.map
|