@zhangly1403/dxfviewer 1.0.0 → 1.2.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.
@@ -32346,9 +32346,10 @@ const trueColorToHex = (trueColor) => {
32346
32346
  return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`.toUpperCase();
32347
32347
  };
32348
32348
  const getAutoCadColor = (index, theme = "black") => {
32349
- if (index <= 0 || index === 256) return theme === "black" ? "#FFFFFF" : "#000000";
32349
+ const bgIsDark = theme === "black" || theme === "gray";
32350
+ if (index <= 0 || index === 256) return bgIsDark ? "#FFFFFF" : "#000000";
32350
32351
  if (index === 7) {
32351
- return theme === "black" ? "#FFFFFF" : "#000000";
32352
+ return bgIsDark ? "#FFFFFF" : "#000000";
32352
32353
  }
32353
32354
  if (index >= 1 && index <= 6) return AUTO_CAD_COLORS[index];
32354
32355
  if (index >= 8 && index <= 9) return AUTO_CAD_COLORS[index];
@@ -34539,7 +34540,8 @@ const getColor = (ent, layer, parentColor, theme) => {
34539
34540
  if (entColor === 0 && parentColor) return parentColor;
34540
34541
  if (entColor === 256 || entColor === void 0) {
34541
34542
  if ((layer == null ? void 0 : layer.trueColor) !== void 0) return trueColorToHex(layer.trueColor);
34542
- return layer ? getAutoCadColor(layer.color, theme) : theme === "black" ? "#FFFFFF" : "#000000";
34543
+ const bgIsDark = theme === "black" || theme === "gray";
34544
+ return layer ? getAutoCadColor(layer.color, theme) : bgIsDark ? "#FFFFFF" : "#000000";
34543
34545
  }
34544
34546
  return getAutoCadColor(entColor, theme);
34545
34547
  };
@@ -34763,7 +34765,9 @@ const drawPolyline = (ctx, points, bulges, closed, transform) => {
34763
34765
  if (closed) ctx.closePath();
34764
34766
  };
34765
34767
  const renderEntitiesToCanvas = (ctx, entities, layers, blocks, styles, lineTypes, ltScale, viewPort, selectedIds, width, height, theme) => {
34766
- ctx.fillStyle = theme === "black" ? "#212121" : "#FFFFFF";
34768
+ if (theme === "white") ctx.fillStyle = "#FFFFFF";
34769
+ else if (theme === "gray") ctx.fillStyle = "#808080";
34770
+ else ctx.fillStyle = "#212121";
34767
34771
  ctx.fillRect(0, 0, width, height);
34768
34772
  const safeZoom = isNaN(viewPort.zoom) || viewPort.zoom === 0 ? 1 : viewPort.zoom;
34769
34773
  const safeTargetX = isNaN(viewPort.targetX) ? 0 : viewPort.targetX;
@@ -35535,9 +35539,26 @@ const ENTITY_TYPE_NAMES = {
35535
35539
  "ACAD_TABLE": "表格 (TABLE)"
35536
35540
  }
35537
35541
  };
35538
- const DxfViewer = ({ entities, layers, blocks = {}, styles = {}, lineTypes = {}, viewPort, onViewPortChange, selectedEntityIds, onSelectIds, worldOffset, ltScale = 1, theme, lang }) => {
35542
+ const DxfViewer = ({
35543
+ entities,
35544
+ layers,
35545
+ blocks = {},
35546
+ styles = {},
35547
+ lineTypes = {},
35548
+ viewPort,
35549
+ onViewPortChange,
35550
+ selectedEntityIds,
35551
+ onSelectIds,
35552
+ worldOffset,
35553
+ ltScale = 1,
35554
+ theme,
35555
+ lang,
35556
+ onMouseMoveWorld
35557
+ }) => {
35539
35558
  const containerRef = useRef(null);
35540
35559
  const canvasRef = useRef(null);
35560
+ const viewPortRef = useRef(viewPort);
35561
+ viewPortRef.current = viewPort;
35541
35562
  const [isPanning, setIsPanning] = useState(false);
35542
35563
  const [isBoxSelecting, setIsBoxSelecting] = useState(false);
35543
35564
  const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
@@ -35556,9 +35577,9 @@ const DxfViewer = ({ entities, layers, blocks = {}, styles = {}, lineTypes = {},
35556
35577
  };
35557
35578
  };
35558
35579
  const [mouseWorldPos, setMouseWorldPos] = useState({ x: 0, y: 0 });
35559
- const displayX = mouseWorldPos.x + ((worldOffset == null ? void 0 : worldOffset.x) || 0);
35560
- const displayY = mouseWorldPos.y + ((worldOffset == null ? void 0 : worldOffset.y) || 0);
35561
- const visibleCount = require$$1.useMemo(() => {
35580
+ mouseWorldPos.x + ((worldOffset == null ? void 0 : worldOffset.x) || 0);
35581
+ mouseWorldPos.y + ((worldOffset == null ? void 0 : worldOffset.y) || 0);
35582
+ require$$1.useMemo(() => {
35562
35583
  return entities.filter((e) => e.visible !== false).length;
35563
35584
  }, [entities]);
35564
35585
  const safeClamp = (value, min, max) => {
@@ -35596,9 +35617,10 @@ const DxfViewer = ({ entities, layers, blocks = {}, styles = {}, lineTypes = {},
35596
35617
  const onWheel = (e) => {
35597
35618
  e.preventDefault();
35598
35619
  const scaleFactor = 1.2;
35599
- const newZoom = e.deltaY < 0 ? viewPort.zoom * scaleFactor : viewPort.zoom / scaleFactor;
35600
- const MIN_ZOOM = Number.MIN_VALUE;
35601
- const MAX_ZOOM = Number.MAX_VALUE;
35620
+ const currentVP = viewPortRef.current;
35621
+ const newZoom = e.deltaY < 0 ? currentVP.zoom * scaleFactor : currentVP.zoom / scaleFactor;
35622
+ const MIN_ZOOM = 1e-50;
35623
+ const MAX_ZOOM = 1e20;
35602
35624
  if (newZoom < MIN_ZOOM || newZoom > MAX_ZOOM) return;
35603
35625
  const rect = container.getBoundingClientRect();
35604
35626
  const mouseX = e.clientX - rect.left;
@@ -35606,8 +35628,8 @@ const DxfViewer = ({ entities, layers, blocks = {}, styles = {}, lineTypes = {},
35606
35628
  const safeZoom2 = Math.max(Math.min(newZoom, MAX_ZOOM), MIN_ZOOM);
35607
35629
  const centerX = rect.width / 2;
35608
35630
  const centerY = rect.height / 2;
35609
- const newTargetX = viewPort.targetX + (mouseX - centerX) * (1 / viewPort.zoom - 1 / safeZoom2);
35610
- const newTargetY = viewPort.targetY - (mouseY - centerY) * (1 / viewPort.zoom - 1 / safeZoom2);
35631
+ const newTargetX = currentVP.targetX + (mouseX - centerX) * (1 / currentVP.zoom - 1 / safeZoom2);
35632
+ const newTargetY = currentVP.targetY - (mouseY - centerY) * (1 / currentVP.zoom - 1 / safeZoom2);
35611
35633
  onViewPortChange({
35612
35634
  targetX: newTargetX,
35613
35635
  targetY: newTargetY,
@@ -35616,7 +35638,7 @@ const DxfViewer = ({ entities, layers, blocks = {}, styles = {}, lineTypes = {},
35616
35638
  };
35617
35639
  container.addEventListener("wheel", onWheel, { passive: false });
35618
35640
  return () => container.removeEventListener("wheel", onWheel);
35619
- }, [viewPort, onViewPortChange]);
35641
+ }, [onViewPortChange]);
35620
35642
  const handleMouseDown = (e) => {
35621
35643
  var _a;
35622
35644
  const rect = (_a = containerRef.current) == null ? void 0 : _a.getBoundingClientRect();
@@ -35641,6 +35663,7 @@ const DxfViewer = ({ entities, layers, blocks = {}, styles = {}, lineTypes = {},
35641
35663
  const mouseY = e.clientY - rect.top;
35642
35664
  const worldPos = screenToWorld(mouseX, mouseY);
35643
35665
  setMouseWorldPos(worldPos);
35666
+ onMouseMoveWorld == null ? void 0 : onMouseMoveWorld(worldPos.x + ((worldOffset == null ? void 0 : worldOffset.x) || 0), worldPos.y + ((worldOffset == null ? void 0 : worldOffset.y) || 0));
35644
35667
  if (isPanning) {
35645
35668
  const dx = e.clientX - dragStart.x;
35646
35669
  const dy = e.clientY - dragStart.y;
@@ -35698,61 +35721,47 @@ const DxfViewer = ({ entities, layers, blocks = {}, styles = {}, lineTypes = {},
35698
35721
  isNaN(viewPort.targetX) ? 0 : viewPort.targetX;
35699
35722
  isNaN(viewPort.targetY) ? 0 : viewPort.targetY;
35700
35723
  isNaN(viewPort.zoom) || viewPort.zoom === 0 ? 1 : viewPort.zoom;
35701
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "viewer-wrapper", children: [
35702
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
35703
- "div",
35704
- {
35705
- ref: containerRef,
35706
- className: `viewer-main flex-1 relative overflow-hidden cursor-crosshair ${theme === "black" ? "bg-[#212121]" : "bg-white"}`,
35707
- onMouseDown: handleMouseDown,
35708
- onMouseMove: handleMouseMove,
35709
- onMouseUp: handleMouseUp,
35710
- onMouseLeave: handleMouseUp,
35711
- onContextMenu: (e) => e.preventDefault(),
35712
- children: [
35713
- /* @__PURE__ */ jsxRuntimeExports.jsx(
35714
- "canvas",
35715
- {
35716
- ref: canvasRef,
35717
- className: "main-canvas"
35718
- }
35719
- ),
35720
- isBoxSelecting && /* @__PURE__ */ jsxRuntimeExports.jsx(
35721
- "div",
35722
- {
35723
- className: "selection-box",
35724
- style: {
35725
- left: Math.min(dragStart.x, currentMousePos.x),
35726
- top: Math.min(dragStart.y, currentMousePos.y),
35727
- width: Math.abs(currentMousePos.x - dragStart.x),
35728
- height: Math.abs(currentMousePos.y - dragStart.y)
35729
- }
35724
+ const getCanvasBg = () => {
35725
+ if (theme === "white") return "#ffffff";
35726
+ if (theme === "gray") return "#808080";
35727
+ return "#212121";
35728
+ };
35729
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "viewer-wrapper", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
35730
+ "div",
35731
+ {
35732
+ ref: containerRef,
35733
+ className: "canvas-container",
35734
+ style: { "--canvas-bg": getCanvasBg() },
35735
+ onMouseDown: handleMouseDown,
35736
+ onMouseMove: handleMouseMove,
35737
+ onMouseUp: handleMouseUp,
35738
+ onMouseLeave: handleMouseUp,
35739
+ onContextMenu: (e) => e.preventDefault(),
35740
+ children: [
35741
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
35742
+ "canvas",
35743
+ {
35744
+ ref: canvasRef,
35745
+ className: "main-canvas"
35746
+ }
35747
+ ),
35748
+ isBoxSelecting && /* @__PURE__ */ jsxRuntimeExports.jsx(
35749
+ "div",
35750
+ {
35751
+ className: "selection-box",
35752
+ style: {
35753
+ left: Math.min(dragStart.x, currentMousePos.x),
35754
+ top: Math.min(dragStart.y, currentMousePos.y),
35755
+ width: Math.abs(currentMousePos.x - dragStart.x),
35756
+ height: Math.abs(currentMousePos.y - dragStart.y)
35730
35757
  }
35731
- )
35732
- ]
35733
- }
35734
- ),
35735
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "status-bar", children: [
35736
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "status-coords", children: [
35737
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
35738
- "X: ",
35739
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "status-value", children: displayX.toFixed(3) })
35740
- ] }),
35741
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
35742
- "Y: ",
35743
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "status-value", children: displayY.toFixed(3) })
35744
- ] })
35745
- ] }),
35746
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "status-spacer" }),
35747
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
35748
- lang === "zh" ? "实体数" : "Entities",
35749
- ": ",
35750
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "status-value", children: visibleCount })
35751
- ] })
35752
- ] })
35753
- ] });
35758
+ }
35759
+ )
35760
+ ]
35761
+ }
35762
+ ) });
35754
35763
  };
35755
- const ROW_HEIGHT = 36;
35764
+ const ROW_HEIGHT = 26;
35756
35765
  const Sidebar = ({ layers, entities, selectedEntityIds, onSelectIds, theme, lang }) => {
35757
35766
  const [expandedLayers, setExpandedLayers] = useState(new Set(Object.keys(layers)));
35758
35767
  const containerRef = useRef(null);
@@ -35909,11 +35918,11 @@ const PropertiesPanel = ({ entities, layers, styles = {}, offset, theme, lang })
35909
35918
  }
35910
35919
  };
35911
35920
  const renderColorValue = (color) => {
35912
- if (color === 256) return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-500", children: "随层 (ByLayer)" });
35913
- if (color === 0) return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-500", children: "随块 (ByBlock)" });
35921
+ if (color === 256) return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--text-secondary)" }, children: "随层 (ByLayer)" });
35922
+ if (color === 0) return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--text-secondary)" }, children: "随块 (ByBlock)" });
35914
35923
  const hex = getAutoCadColor(color || 7, theme);
35915
35924
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "color-preview-container", children: [
35916
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-gray-400 text-xs", children: [
35925
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { style: { color: "var(--text-secondary)", fontSize: "10px" }, children: [
35917
35926
  "(",
35918
35927
  color,
35919
35928
  ")"
@@ -35929,9 +35938,9 @@ const PropertiesPanel = ({ entities, layers, styles = {}, offset, theme, lang })
35929
35938
  ] });
35930
35939
  };
35931
35940
  const renderLineweight = (lw) => {
35932
- if (lw === void 0 || lw === -1) return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-500", children: "随层 (ByLayer)" });
35933
- if (lw === -2) return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-500", children: "随块 (ByBlock)" });
35934
- if (lw === -3) return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-gray-500", children: "默认 (Default)" });
35941
+ if (lw === void 0 || lw === -1) return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--text-secondary)" }, children: "随层 (ByLayer)" });
35942
+ if (lw === -2) return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--text-secondary)" }, children: "随块 (ByBlock)" });
35943
+ if (lw === -3) return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--text-secondary)" }, children: "默认 (Default)" });
35935
35944
  if (lw === 0) return "0.00 mm";
35936
35945
  return `${(lw / 100).toFixed(2)} mm`;
35937
35946
  };
@@ -35943,7 +35952,7 @@ const PropertiesPanel = ({ entities, layers, styles = {}, offset, theme, lang })
35943
35952
  var _a, _b;
35944
35953
  const typeDisplay = entNames[ent.type] || ent.type;
35945
35954
  const commonRows = [
35946
- renderPropertyRow("Type", /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-blue-600 font-bold", children: typeDisplay })),
35955
+ renderPropertyRow("Type", /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--accent-blue)", fontWeight: "bold" }, children: typeDisplay })),
35947
35956
  renderPropertyRow("Handle", formatHandle(ent.handle)),
35948
35957
  renderPropertyRow("Layer", ent.layer),
35949
35958
  renderPropertyRow("Color", renderColorValue(ent.color)),
@@ -36076,8 +36085,10 @@ const ToolBar = ({
36076
36085
  showProperties,
36077
36086
  onToggleProperties,
36078
36087
  showOpen = true,
36079
- theme,
36080
- onToggleTheme,
36088
+ uiTheme,
36089
+ onSetUiTheme,
36090
+ canvasTheme,
36091
+ onSetCanvasTheme,
36081
36092
  lang,
36082
36093
  onSetLang
36083
36094
  }) => {
@@ -36087,7 +36098,7 @@ const ToolBar = ({
36087
36098
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
36088
36099
  "div",
36089
36100
  {
36090
- className: "menu-item",
36101
+ className: `menu-item ${activeMenu === "file" ? "active" : ""}`,
36091
36102
  onMouseEnter: () => setActiveMenu("file"),
36092
36103
  onMouseLeave: () => setActiveMenu(null),
36093
36104
  children: [
@@ -36105,7 +36116,7 @@ const ToolBar = ({
36105
36116
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
36106
36117
  "div",
36107
36118
  {
36108
- className: "menu-item",
36119
+ className: `menu-item ${activeMenu === "view" ? "active" : ""}`,
36109
36120
  onMouseEnter: () => setActiveMenu("view"),
36110
36121
  onMouseLeave: () => setActiveMenu(null),
36111
36122
  children: [
@@ -36113,26 +36124,6 @@ const ToolBar = ({
36113
36124
  activeMenu === "view" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "dropdown-menu", style: { minWidth: "160px" }, children: [
36114
36125
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: onFitView, className: "dropdown-item", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t.fitView }) }),
36115
36126
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "divider" }),
36116
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: onToggleSidebar, className: "dropdown-item", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
36117
- t.layers,
36118
- " (",
36119
- showSidebar ? t.off : t.on,
36120
- ")"
36121
- ] }) }),
36122
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: onToggleProperties, className: "dropdown-item", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
36123
- t.properties,
36124
- " (",
36125
- showProperties ? t.off : t.on,
36126
- ")"
36127
- ] }) }),
36128
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "divider" }),
36129
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: onToggleTheme, className: "dropdown-item", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
36130
- t.theme,
36131
- " (",
36132
- theme === "black" ? t.black : t.white,
36133
- ")"
36134
- ] }) }),
36135
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "divider" }),
36136
36127
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: () => onSetLang(lang === "zh" ? "en" : "zh"), className: "dropdown-item", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
36137
36128
  t.language,
36138
36129
  ": ",
@@ -36141,6 +36132,41 @@ const ToolBar = ({
36141
36132
  ] })
36142
36133
  ]
36143
36134
  }
36135
+ ),
36136
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
36137
+ "div",
36138
+ {
36139
+ className: `menu-item ${activeMenu === "interface" ? "active" : ""}`,
36140
+ onMouseEnter: () => setActiveMenu("interface"),
36141
+ onMouseLeave: () => setActiveMenu(null),
36142
+ children: [
36143
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: lang === "zh" ? "界面" : "Interface" }),
36144
+ activeMenu === "interface" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "dropdown-menu", style: { minWidth: "180px" }, children: [
36145
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: onToggleSidebar, className: `dropdown-item ${showSidebar ? "checked" : ""}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t.layers }) }),
36146
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: onToggleProperties, className: `dropdown-item ${showProperties ? "checked" : ""}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t.properties }) }),
36147
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "divider" }),
36148
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: () => onSetUiTheme("light"), className: `dropdown-item ${uiTheme === "light" ? "checked" : ""}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: lang === "zh" ? "浅色模式" : "Light Mode" }) }),
36149
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: () => onSetUiTheme("dark"), className: `dropdown-item ${uiTheme === "dark" ? "checked" : ""}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: lang === "zh" ? "深色模式" : "Dark Mode" }) })
36150
+ ] })
36151
+ ]
36152
+ }
36153
+ ),
36154
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
36155
+ "div",
36156
+ {
36157
+ className: `menu-item ${activeMenu === "settings" ? "active" : ""}`,
36158
+ onMouseEnter: () => setActiveMenu("settings"),
36159
+ onMouseLeave: () => setActiveMenu(null),
36160
+ children: [
36161
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: lang === "zh" ? "设置" : "Settings" }),
36162
+ activeMenu === "settings" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "dropdown-menu", style: { minWidth: "180px" }, children: [
36163
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "dropdown-header", style: { padding: "4px 12px", fontSize: "10px", color: "var(--text-secondary)" }, children: lang === "zh" ? "背景颜色" : "Background Color" }),
36164
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: () => onSetCanvasTheme("black"), className: `dropdown-item ${canvasTheme === "black" ? "checked" : ""}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: lang === "zh" ? "黑色" : "Black" }) }),
36165
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: () => onSetCanvasTheme("white"), className: `dropdown-item ${canvasTheme === "white" ? "checked" : ""}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: lang === "zh" ? "白色" : "White" }) }),
36166
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { onClick: () => onSetCanvasTheme("gray"), className: `dropdown-item ${canvasTheme === "gray" ? "checked" : ""}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: lang === "zh" ? "灰色" : "Gray" }) })
36167
+ ] })
36168
+ ]
36169
+ }
36144
36170
  )
36145
36171
  ] });
36146
36172
  };
@@ -36171,8 +36197,13 @@ const DxfViewerMain = ({
36171
36197
  const [showSidebar, setShowSidebar] = useState(true);
36172
36198
  const [showProperties, setShowProperties] = useState(true);
36173
36199
  const [viewPort, setViewPort] = useState(DEFAULT_VIEWPORT);
36174
- const [theme, setTheme] = useState("black");
36200
+ const [uiTheme, setUiTheme] = useState("light");
36201
+ const [canvasTheme, setCanvasTheme] = useState("black");
36175
36202
  const [internalLang, setInternalLang] = useState(defaultLanguage);
36203
+ const [mouseCoords, setMouseCoords] = useState({ x: 0, y: 0 });
36204
+ const [isExporting, setIsExporting] = useState(false);
36205
+ const containerRef = useRef(null);
36206
+ const viewerRef = useRef(null);
36176
36207
  const lang = controlledLang || internalLang;
36177
36208
  const handleSetLang = useCallback((newLang) => {
36178
36209
  setInternalLang(newLang);
@@ -36185,12 +36216,23 @@ const DxfViewerMain = ({
36185
36216
  const extents = calculateSmartExtents(visibleEnts, blks);
36186
36217
  const centerX = extents.center.x;
36187
36218
  const centerY = extents.center.y;
36188
- const sidebarWidth = showSidebar ? 256 : 0;
36189
- const propsWidth = showProperties ? 320 : 0;
36190
- const containerW = Math.max(window.innerWidth - sidebarWidth - propsWidth, 100);
36191
- const containerH = Math.max(window.innerHeight - 40, 100);
36219
+ let containerW = window.innerWidth;
36220
+ let containerH = window.innerHeight;
36221
+ if (viewerRef.current) {
36222
+ const rect = viewerRef.current.getBoundingClientRect();
36223
+ containerW = rect.width;
36224
+ containerH = rect.height;
36225
+ } else if (containerRef.current) {
36226
+ const rect = containerRef.current.getBoundingClientRect();
36227
+ const sidebarWidth = showSidebar ? 256 : 0;
36228
+ const propsWidth = showProperties ? 320 : 0;
36229
+ containerW = rect.width - sidebarWidth - propsWidth;
36230
+ containerH = rect.height - 30 - 24;
36231
+ }
36232
+ containerW = Math.max(containerW, 100);
36233
+ containerH = Math.max(containerH, 100);
36192
36234
  if (extents.width <= 0 && extents.height <= 0) {
36193
- setViewPort({ targetX: centerX, targetY: centerY, zoom: 1 });
36235
+ setViewPort((prev) => ({ ...prev, targetX: centerX, targetY: centerY, zoom: 1 }));
36194
36236
  return;
36195
36237
  }
36196
36238
  const worldW = extents.width;
@@ -36279,10 +36321,23 @@ const DxfViewerMain = ({
36279
36321
  fitView(entities, blocks);
36280
36322
  }
36281
36323
  };
36324
+ const observer = new ResizeObserver((entries) => {
36325
+ requestAnimationFrame(() => {
36326
+ handleResize();
36327
+ });
36328
+ });
36329
+ if (viewerRef.current) {
36330
+ observer.observe(viewerRef.current);
36331
+ } else if (containerRef.current) {
36332
+ observer.observe(containerRef.current);
36333
+ }
36282
36334
  window.addEventListener("resize", handleResize);
36283
36335
  handleResize();
36284
- return () => window.removeEventListener("resize", handleResize);
36285
- }, [entities, blocks, fitView, showSidebar, showProperties]);
36336
+ return () => {
36337
+ window.removeEventListener("resize", handleResize);
36338
+ observer.disconnect();
36339
+ };
36340
+ }, [entities, blocks, fitView]);
36286
36341
  useEffect(() => {
36287
36342
  if (initFile) {
36288
36343
  if (typeof initFile === "string") {
@@ -36302,7 +36357,7 @@ const DxfViewerMain = ({
36302
36357
  const sidebarWidth = showSidebar ? 256 : 0;
36303
36358
  const propsWidth = showProperties ? 320 : 0;
36304
36359
  const containerW = window.innerWidth - sidebarWidth - propsWidth;
36305
- const containerH = window.innerHeight - 40;
36360
+ const containerH = window.innerHeight - 30 - 24;
36306
36361
  const w = extents.width;
36307
36362
  const h = extents.height;
36308
36363
  if (w > 0 || h > 0) {
@@ -36372,7 +36427,7 @@ const DxfViewerMain = ({
36372
36427
  e.target.value = "";
36373
36428
  };
36374
36429
  const selectedEntities = entities.filter((e) => selectedEntityIds.has(e.id));
36375
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "app-container", children: [
36430
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref: containerRef, className: `app-container ${uiTheme === "dark" ? "theme-dark" : ""}`, children: [
36376
36431
  isLoading && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "loading-overlay", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "loading-box", children: [
36377
36432
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "loading-text", children: "正在解析 DXF..." }),
36378
36433
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "progress-bar-container", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -36398,13 +36453,15 @@ const DxfViewerMain = ({
36398
36453
  showProperties,
36399
36454
  onToggleProperties: () => setShowProperties(!showProperties),
36400
36455
  showOpen: showOpenMenu,
36401
- theme,
36402
- onToggleTheme: () => setTheme(theme === "black" ? "white" : "black"),
36456
+ uiTheme,
36457
+ onSetUiTheme: setUiTheme,
36458
+ canvasTheme,
36459
+ onSetCanvasTheme: setCanvasTheme,
36403
36460
  lang,
36404
36461
  onSetLang: handleSetLang
36405
36462
  }
36406
36463
  ),
36407
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "main-content", style: { height: "calc(100vh - 40px)" }, children: [
36464
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "main-content", children: [
36408
36465
  showSidebar && /* @__PURE__ */ jsxRuntimeExports.jsx(
36409
36466
  Sidebar,
36410
36467
  {
@@ -36412,11 +36469,11 @@ const DxfViewerMain = ({
36412
36469
  entities,
36413
36470
  selectedEntityIds,
36414
36471
  onSelectIds: handleSidebarSelectIds,
36415
- theme,
36472
+ theme: canvasTheme,
36416
36473
  lang
36417
36474
  }
36418
36475
  ),
36419
- /* @__PURE__ */ jsxRuntimeExports.jsx("main", { className: `viewer-container shadow-inner flex flex-col border-l border-r border-gray-300 ${theme === "black" ? "bg-[#212121]" : "bg-white"}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
36476
+ /* @__PURE__ */ jsxRuntimeExports.jsx("main", { ref: viewerRef, className: "viewer-container", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
36420
36477
  DxfViewer,
36421
36478
  {
36422
36479
  entities,
@@ -36431,8 +36488,9 @@ const DxfViewerMain = ({
36431
36488
  onSelectIds: setSelectedEntityIds,
36432
36489
  onFitView: handleFitView,
36433
36490
  worldOffset,
36434
- theme,
36435
- lang
36491
+ theme: canvasTheme,
36492
+ lang,
36493
+ onMouseMoveWorld: (x, y) => setMouseCoords({ x, y })
36436
36494
  }
36437
36495
  ) }),
36438
36496
  showProperties && /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -36442,10 +36500,34 @@ const DxfViewerMain = ({
36442
36500
  layers: Object.values(layers),
36443
36501
  styles,
36444
36502
  offset: worldOffset,
36445
- theme,
36503
+ theme: canvasTheme,
36446
36504
  lang
36447
36505
  }
36448
36506
  )
36507
+ ] }),
36508
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "status-bar", children: [
36509
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "status-left", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "status-coords", children: [
36510
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
36511
+ "X: ",
36512
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "status-value", children: mouseCoords.x.toFixed(3) })
36513
+ ] }),
36514
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
36515
+ "Y: ",
36516
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "status-value", children: mouseCoords.y.toFixed(3) })
36517
+ ] })
36518
+ ] }) }),
36519
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "status-center", children: selectedEntityIds.size === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: lang === "zh" ? "未选择对象" : "No objects selected" }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", gap: "15px", alignItems: "center" }, children: [
36520
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: lang === "zh" ? `已选择 ${selectedEntityIds.size} 个对象` : `Selected ${selectedEntityIds.size} objects` }),
36521
+ selectedEntityIds.size === 1 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { opacity: 0.8, fontSize: "10px" }, children: lang === "zh" ? "选择单个对象以查看详细属性" : "Select a single object to view detailed properties" })
36522
+ ] }) }),
36523
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "status-right", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", gap: "20px" }, children: [
36524
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
36525
+ lang === "zh" ? "实体数" : "Entities",
36526
+ ": ",
36527
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "status-value", children: entities.length })
36528
+ ] }),
36529
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { opacity: 0.8 }, children: lang === "zh" ? "就绪" : "Ready" })
36530
+ ] }) })
36449
36531
  ] })
36450
36532
  ] });
36451
36533
  };