diff --git a/src/App.jsx b/src/App.jsx
index c9743ed..1f0c71f 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -3,7 +3,8 @@ import { Stage, Layer, Group } from 'react-konva';
import { RoomPolygon } from './RoomPolygon';
import { Tile } from './Tile';
import { computeRoomVertices } from './utils/geometry';
-import { Settings2, Plus, Trash2, Download, Upload } from 'lucide-react';
+import { Settings2, Plus, Trash2, Download, Upload, Camera } from 'lucide-react';
+
// Fixed real-world side lengths in meters (+ 180° CW: A←C, B←D, C←A, D←B)
const SCALE = 70; // 70 pixels per meter
@@ -16,7 +17,7 @@ function App() {
const SIDE_C = isReducedSize ? 4.50 : 10.40;
const SIDE_D = 4.93;
- const [alphaDeg, setAlphaDeg] = useState(90);
+ const alphaDeg = 90;
const [tiles, setTiles] = useState([]);
const [selectedId, setSelectedId] = useState(null);
const [dimensions, setDimensions] = useState({ width: 800, height: 600 });
@@ -28,6 +29,63 @@ function App() {
const count240x120 = tiles.filter(t => t.width === 2.4 && t.height === 1.2).length;
const countLights = tiles.filter(t => t.type === 'light').length;
const containerRef = useRef(null);
+ const stageRef = useRef(null);
+
+ const downloadScreenshot = () => {
+ if (stageRef.current) {
+ const currentSelectedId = selectedId;
+ setSelectedId(null);
+
+ // Force a slight delay to allow React to render without selection border
+ setTimeout(() => {
+ const stage = stageRef.current;
+ const stageCanvas = stage.toCanvas({ pixelRatio: 2 });
+
+ const exportCanvas = document.createElement('canvas');
+ exportCanvas.width = stageCanvas.width;
+ exportCanvas.height = stageCanvas.height;
+ const ctx = exportCanvas.getContext('2d');
+
+ // Background color matching the dark theme
+ ctx.fillStyle = '#0f172a';
+ ctx.fillRect(0, 0, exportCanvas.width, exportCanvas.height);
+
+ // Draw the matching grid dots
+ const dotSpacing = 24 * 2;
+ const dotRadius = 1 * 2;
+ ctx.fillStyle = 'rgba(51, 65, 85, 0.3)';
+
+ const stageX = stage.x() * 2;
+ const stageY = stage.y() * 2;
+ const startX = stageX % dotSpacing;
+ const startY = stageY % dotSpacing;
+
+ for (let x = startX - dotSpacing; x < exportCanvas.width + dotSpacing; x += dotSpacing) {
+ for (let y = startY - dotSpacing; y < exportCanvas.height + dotSpacing; y += dotSpacing) {
+ ctx.beginPath();
+ ctx.arc(x, y, dotRadius, 0, Math.PI * 2);
+ ctx.fill();
+ }
+ }
+
+ // Draw the stage on top
+ ctx.drawImage(stageCanvas, 0, 0);
+
+ // Create download link
+ const dataUrl = exportCanvas.toDataURL('image/png');
+ const downloadAnchorNode = document.createElement('a');
+ downloadAnchorNode.setAttribute("href", dataUrl);
+ downloadAnchorNode.setAttribute("download", "room-layout.png");
+ document.body.appendChild(downloadAnchorNode);
+ downloadAnchorNode.click();
+ downloadAnchorNode.remove();
+
+ // Restore selection
+ setSelectedId(currentSelectedId);
+ }, 50);
+ }
+ };
+
// Responsive canvas size
useEffect(() => {
@@ -77,8 +135,6 @@ function App() {
};
const addTile = (width, height, label) => {
- const isSquare = width === height;
-
// Assign colors based on dimensions
let color = "rgba(16, 185, 129, 0.6)"; // Default Green
let stroke = "#10b981";
@@ -264,6 +320,10 @@ function App() {
Exportieren...
+
+