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