Verwobenheit: Farb-Konfigurator
Hier erscheint dein präziser Prompt...
import React, { useMemo, useState } from "react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { Undo2, MousePointer2, Route, Home, Type, Trash2 } from "lucide-react";
const svgWidth = 1200;
const svgHeight = 900;
const roadX = 500;
const roadTop = 80;
const roadBottom = 820;
const houseWidth = 34;
const houseHeight = 90;
const sideRoadLength = 70;
const labelGap = 18;
const houseGap = 18;
const clickSnap = 10;
function snap(v) {
return Math.round(v / clickSnap) * clickSnap;
}
function uid() {
return Math.random().toString(36).slice(2, 10);
}
export default function OstertorsteinwegZeichenprogramm() {
const [tool, setTool] = useState("side-road");
const [roadName, setRoadName] = useState("Ostertorsteinweg");
const [sideRoads, setSideRoads] = useState([]);
const [houses, setHouses] = useState([]);
const [history, setHistory] = useState([]);
const pushHistory = () => {
setHistory((h) => [
...h,
{
sideRoads: JSON.parse(JSON.stringify(sideRoads)),
houses: JSON.parse(JSON.stringify(houses)),
},
]);
};
const undo = () => {
setHistory((h) => {
if (!h.length) return h;
const prev = h[h.length - 1];
setSideRoads(prev.sideRoads);
setHouses(prev.houses);
return h.slice(0, -1);
});
};
const clearAll = () => {
pushHistory();
setSideRoads([]);
setHouses([]);
};
const occupiedBands = useMemo(() => {
return {
sideRoads: sideRoads.map((s) => s.y),
houses: houses.map((h) => h.y),
};
}, [sideRoads, houses]);
const handleSvgClick = (e) => {
const rect = e.currentTarget.getBoundingClientRect();
const scaleX = svgWidth / rect.width;
const scaleY = svgHeight / rect.height;
const x = (e.clientX - rect.left) * scaleX;
const y = snap((e.clientY - rect.top) * scaleY);
if (y < roadTop + 10 || y > roadBottom - 10) return;
if (tool === "side-road") {
const side = x >= roadX ? "right" : "left";
pushHistory();
setSideRoads((prev) => [
...prev,
{ id: uid(), y, side, name: "", editing: true },
]);
return;
}
if (tool === "house") {
const side = x >= roadX ? "right" : "left";
pushHistory();
setHouses((prev) => [
...prev,
{ id: uid(), y, side, number: "", editing: true },
]);
}
};
const updateSideRoad = (id, patch) => {
setSideRoads((prev) => prev.map((s) => (s.id === id ? { ...s, ...patch } : s)));
};
const updateHouse = (id, patch) => {
setHouses((prev) => prev.map((h) => (h.id === id ? { ...h, ...patch } : h)));
};
const deleteSideRoad = (id) => {
pushHistory();
setSideRoads((prev) => prev.filter((s) => s.id !== id));
};
const deleteHouse = (id) => {
pushHistory();
setHouses((prev) => prev.filter((h) => h.id !== id));
};
const sortedSideRoads = [...sideRoads].sort((a, b) => a.y - b.y);
const sortedHouses = [...houses].sort((a, b) => a.y - b.y);
return ( Zeichenprogramm
v && setTool(v)}
className="grid grid-cols-2 gap-2"
>
Auswahl
Nebenstraße
Haus
Zeichenfläche
);
}
setRoadName(e.target.value)} />
Werkzeug
Klicke in die Zeichenfläche.
Nebenstraße: Es erscheint automatisch ein Strich und ein Eingabefeld für den Namen.
Haus: Es erscheint automatisch ein Rechteck und ein Eingabefeld für die Hausnummer.
Mit Enter verschwindet das jeweilige Eingabefeld.
Nebenstraße: Es erscheint automatisch ein Strich und ein Eingabefeld für den Namen.
Haus: Es erscheint automatisch ein Rechteck und ein Eingabefeld für die Hausnummer.
Mit Enter verschwindet das jeweilige Eingabefeld.
Nebenstraßen
{sortedSideRoads.length === 0 ? (
))
)}
Noch keine Nebenstraßen.
) : (
sortedSideRoads.map((s) => ( {s.name || "Ohne Namen"}
{s.side === "left" ? "links" : "rechts"} · y {s.y}
Häuser
{sortedHouses.length === 0 ? (
))
)}
Noch keine Häuser.
) : (
sortedHouses.map((h) => ( {h.number || "Ohne Nummer"}
{h.side === "left" ? "links" : "rechts"} · y {h.y}
