feat: Implement initial application structure with network view and SVG editor
- Added network-view.js for visualizing network topology with devices and connections. - Introduced svg-editor.js for managing ports on device types with drag-and-drop functionality. - Created bootstrap.php for application initialization, including configuration and database connection. - Established config.php for centralized configuration settings. - Developed index.php as the main entry point with module-based routing. - Integrated _sql.php for database abstraction. - Added auth.php for single-user authentication handling. - Included helpers.php for utility functions. - Created modules for managing connections, device types, devices, and floors. - Implemented database schema in init.sql for locations, buildings, floors, rooms, network outlets, devices, and connections. - Added Docker support with docker-compose.yml for web and database services. - Documented database structure and UI/UX concepts in respective markdown files.
This commit is contained in:
258
app/assets/js/svg-editor.js
Normal file
258
app/assets/js/svg-editor.js
Normal file
@@ -0,0 +1,258 @@
|
||||
// Logik für den SVG-Port-Editor (Klicks, Drag & Drop, Speichern)
|
||||
/**
|
||||
* svg-editor.js
|
||||
*
|
||||
* Logik für den SVG-Port-Editor:
|
||||
* - Ports per Klick anlegen
|
||||
* - Ports auswählen
|
||||
* - Ports verschieben (Drag & Drop)
|
||||
* - Ports löschen
|
||||
* - Ports laden / speichern
|
||||
*
|
||||
* Abhängigkeiten: keine (Vanilla JS)
|
||||
*/
|
||||
|
||||
/* =========================
|
||||
* Konfiguration
|
||||
* ========================= */
|
||||
|
||||
// TODO: vom Backend setzen (z. B. via data-Attribut)
|
||||
const DEVICE_TYPE_ID = null;
|
||||
|
||||
// TODO: API-Endpunkte festlegen
|
||||
const API_LOAD_PORTS = '/api/device_type_ports.php?action=load';
|
||||
const API_SAVE_PORTS = '/api/device_type_ports.php?action=save';
|
||||
|
||||
/* =========================
|
||||
* State
|
||||
* ========================= */
|
||||
|
||||
let svgElement = null;
|
||||
let ports = [];
|
||||
let selectedPortId = null;
|
||||
let isDragging = false;
|
||||
let dragOffset = { x: 0, y: 0 };
|
||||
|
||||
/* =========================
|
||||
* Initialisierung
|
||||
* ========================= */
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
svgElement = document.querySelector('#device-svg');
|
||||
|
||||
if (!svgElement) {
|
||||
console.warn('SVG Editor: #device-svg nicht gefunden');
|
||||
return;
|
||||
}
|
||||
|
||||
bindSvgEvents();
|
||||
loadPorts();
|
||||
});
|
||||
|
||||
/* =========================
|
||||
* SVG Events
|
||||
* ========================= */
|
||||
|
||||
function bindSvgEvents() {
|
||||
svgElement.addEventListener('click', onSvgClick);
|
||||
svgElement.addEventListener('mousemove', onSvgMouseMove);
|
||||
svgElement.addEventListener('mouseup', onSvgMouseUp);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Port-Erstellung
|
||||
* ========================= */
|
||||
|
||||
function onSvgClick(event) {
|
||||
// Klick auf bestehenden Port?
|
||||
if (event.target.classList.contains('port-point')) {
|
||||
selectPort(event.target.dataset.id);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Modifier-Key prüfen (z. B. nur mit SHIFT neuen Port erstellen?)
|
||||
const point = getSvgCoordinates(event);
|
||||
|
||||
createPort(point.x, point.y);
|
||||
}
|
||||
|
||||
function createPort(x, y) {
|
||||
const id = generateTempId();
|
||||
|
||||
const port = {
|
||||
id: id,
|
||||
name: `Port ${ports.length + 1}`,
|
||||
port_type_id: null, // TODO: Default-Porttyp?
|
||||
x: x,
|
||||
y: y,
|
||||
comment: ''
|
||||
};
|
||||
|
||||
ports.push(port);
|
||||
renderPort(port);
|
||||
selectPort(id);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Rendering
|
||||
* ========================= */
|
||||
|
||||
function renderPort(port) {
|
||||
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
|
||||
|
||||
circle.setAttribute('cx', port.x);
|
||||
circle.setAttribute('cy', port.y);
|
||||
circle.setAttribute('r', 6);
|
||||
circle.classList.add('port-point');
|
||||
circle.dataset.id = port.id;
|
||||
|
||||
circle.addEventListener('mousedown', (e) => {
|
||||
startDrag(e, port.id);
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
svgElement.appendChild(circle);
|
||||
}
|
||||
|
||||
function rerenderPorts() {
|
||||
svgElement.querySelectorAll('.port-point').forEach(p => p.remove());
|
||||
ports.forEach(renderPort);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Auswahl
|
||||
* ========================= */
|
||||
|
||||
function selectPort(id) {
|
||||
selectedPortId = id;
|
||||
|
||||
document.querySelectorAll('.port-point').forEach(el => {
|
||||
el.classList.toggle('selected', el.dataset.id === id);
|
||||
});
|
||||
|
||||
// TODO: Sidebar-Felder mit Portdaten füllen
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Drag & Drop
|
||||
* ========================= */
|
||||
|
||||
function startDrag(event, portId) {
|
||||
const port = getPortById(portId);
|
||||
if (!port) return;
|
||||
|
||||
isDragging = true;
|
||||
selectedPortId = portId;
|
||||
|
||||
const point = getSvgCoordinates(event);
|
||||
dragOffset.x = port.x - point.x;
|
||||
dragOffset.y = port.y - point.y;
|
||||
}
|
||||
|
||||
function onSvgMouseMove(event) {
|
||||
if (!isDragging || !selectedPortId) return;
|
||||
|
||||
const port = getPortById(selectedPortId);
|
||||
if (!port) return;
|
||||
|
||||
const point = getSvgCoordinates(event);
|
||||
|
||||
port.x = point.x + dragOffset.x;
|
||||
port.y = point.y + dragOffset.y;
|
||||
|
||||
rerenderPorts();
|
||||
}
|
||||
|
||||
function onSvgMouseUp() {
|
||||
isDragging = false;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Löschen
|
||||
* ========================= */
|
||||
|
||||
function deleteSelectedPort() {
|
||||
if (!selectedPortId) return;
|
||||
|
||||
// TODO: Sicherheitsabfrage (confirm)
|
||||
ports = ports.filter(p => p.id !== selectedPortId);
|
||||
selectedPortId = null;
|
||||
|
||||
rerenderPorts();
|
||||
|
||||
// TODO: Sidebar zurücksetzen
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Laden / Speichern
|
||||
* ========================= */
|
||||
|
||||
function loadPorts() {
|
||||
if (!DEVICE_TYPE_ID) {
|
||||
console.warn('DEVICE_TYPE_ID nicht gesetzt');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`${API_LOAD_PORTS}&device_type_id=${DEVICE_TYPE_ID}`)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
// TODO: Datenformat validieren
|
||||
ports = data;
|
||||
rerenderPorts();
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Fehler beim Laden der Ports', err);
|
||||
});
|
||||
}
|
||||
|
||||
function savePorts() {
|
||||
if (!DEVICE_TYPE_ID) return;
|
||||
|
||||
fetch(API_SAVE_PORTS, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
device_type_id: DEVICE_TYPE_ID,
|
||||
ports: ports
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
// TODO: Erfolg / Fehler anzeigen
|
||||
console.log('Ports gespeichert', data);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Fehler beim Speichern', err);
|
||||
});
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Hilfsfunktionen
|
||||
* ========================= */
|
||||
|
||||
function getSvgCoordinates(event) {
|
||||
const pt = svgElement.createSVGPoint();
|
||||
pt.x = event.clientX;
|
||||
pt.y = event.clientY;
|
||||
|
||||
const transformed = pt.matrixTransform(svgElement.getScreenCTM().inverse());
|
||||
return { x: transformed.x, y: transformed.y };
|
||||
}
|
||||
|
||||
function getPortById(id) {
|
||||
return ports.find(p => p.id === id);
|
||||
}
|
||||
|
||||
function generateTempId() {
|
||||
return 'tmp_' + Math.random().toString(36).substr(2, 9);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Keyboard Shortcuts
|
||||
* ========================= */
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Delete') {
|
||||
deleteSelectedPort();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user