3
NEXT.md
3
NEXT.md
@@ -1,6 +1,9 @@
|
|||||||
# NEXT_STEPS
|
# NEXT_STEPS
|
||||||
|
|
||||||
## Aktive Aufgaben (priorisiert)
|
## Aktive Aufgaben (priorisiert)
|
||||||
|
- [x] [#24] infrastruktur stockerkkarte zoomen wird die grundrisskarten overlay nicht mitgezoomt
|
||||||
|
- [x] [#23] netzwerkdosen haben nur port 1 und brauche in den auswahlen nicht mit port 1 angezeigt zu werden
|
||||||
|
- [x] [#22] für neue verbindungen nur ports anbieten die noch keine verbingung haben
|
||||||
- [x] [#20] Gesamt-Topologie-Wand im dashboard ist schwarze
|
- [x] [#20] Gesamt-Topologie-Wand im dashboard ist schwarze
|
||||||
- [x] [#19] gerät nicht löschbar wegen ports, ports sind aber nicht löschbar
|
- [x] [#19] gerät nicht löschbar wegen ports, ports sind aber nicht löschbar
|
||||||
- [x] [#18] wandbuchsen direkt beim erstellen schon an patchpanel bindfen
|
- [x] [#18] wandbuchsen direkt beim erstellen schon an patchpanel bindfen
|
||||||
|
|||||||
@@ -30,10 +30,6 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
.floor-plan-toolbar {
|
|
||||||
display: flex;
|
|
||||||
gap: 6px;
|
|
||||||
}
|
|
||||||
.floor-plan-canvas {
|
.floor-plan-canvas {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -48,17 +44,6 @@
|
|||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.floor-plan-svg {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 0;
|
|
||||||
opacity: 0.75;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
.floor-plan-overlay {
|
.floor-plan-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
@@ -67,6 +52,10 @@
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
}
|
}
|
||||||
|
.floor-plan-overlay .floor-plan-background {
|
||||||
|
opacity: 0.75;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
.floor-plan-overlay .active-marker {
|
.floor-plan-overlay .active-marker {
|
||||||
cursor: move;
|
cursor: move;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,18 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
let viewWidth = DEFAULT_PLAN_SIZE.width;
|
let viewWidth = DEFAULT_PLAN_SIZE.width;
|
||||||
let viewHeight = DEFAULT_PLAN_SIZE.height;
|
let viewHeight = DEFAULT_PLAN_SIZE.height;
|
||||||
|
|
||||||
|
overlay.setAttribute('preserveAspectRatio', 'none');
|
||||||
|
|
||||||
|
const backgroundImage = document.createElementNS(SVG_NS, 'image');
|
||||||
|
backgroundImage.classList.add('floor-plan-background');
|
||||||
|
backgroundImage.setAttribute('x', '0');
|
||||||
|
backgroundImage.setAttribute('y', '0');
|
||||||
|
backgroundImage.setAttribute('width', String(DEFAULT_PLAN_SIZE.width));
|
||||||
|
backgroundImage.setAttribute('height', String(DEFAULT_PLAN_SIZE.height));
|
||||||
|
backgroundImage.setAttribute('preserveAspectRatio', 'none');
|
||||||
|
backgroundImage.setAttribute('display', 'none');
|
||||||
|
overlay.appendChild(backgroundImage);
|
||||||
|
|
||||||
const activeMarker = document.createElementNS(SVG_NS, 'rect');
|
const activeMarker = document.createElementNS(SVG_NS, 'rect');
|
||||||
activeMarker.classList.add('active-marker');
|
activeMarker.classList.add('active-marker');
|
||||||
if (markerType === 'patchpanel') {
|
if (markerType === 'patchpanel') {
|
||||||
@@ -237,7 +249,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const panelBuildingSelect = document.getElementById('panel-building-select');
|
const panelBuildingSelect = document.getElementById('panel-building-select');
|
||||||
const panelFloorSelect = document.getElementById('panel-floor-select');
|
const panelFloorSelect = document.getElementById('panel-floor-select');
|
||||||
const outletRoomSelect = document.getElementById('outlet-room-select');
|
const outletRoomSelect = document.getElementById('outlet-room-select');
|
||||||
const floorPlanSvg = document.getElementById('floor-plan-svg');
|
|
||||||
const panelPlacementFields = document.getElementById('panel-placement-fields');
|
const panelPlacementFields = document.getElementById('panel-placement-fields');
|
||||||
const panelFloorPlanGroup = document.getElementById('panel-floor-plan-group');
|
const panelFloorPlanGroup = document.getElementById('panel-floor-plan-group');
|
||||||
const panelFloorMissingHint = document.getElementById('panel-floor-missing-hint');
|
const panelFloorMissingHint = document.getElementById('panel-floor-missing-hint');
|
||||||
@@ -312,21 +323,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateFloorPlanImage = () => {
|
const updateFloorPlanImage = () => {
|
||||||
if (!floorPlanSvg) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const floorOption = panelFloorSelect?.selectedOptions?.[0];
|
const floorOption = panelFloorSelect?.selectedOptions?.[0];
|
||||||
const roomOption = outletRoomSelect?.selectedOptions?.[0];
|
const roomOption = outletRoomSelect?.selectedOptions?.[0];
|
||||||
const svgUrl = floorOption?.dataset?.svgUrl || roomOption?.dataset?.floorSvgUrl || '';
|
const svgUrl = floorOption?.dataset?.svgUrl || roomOption?.dataset?.floorSvgUrl || '';
|
||||||
|
|
||||||
if (svgUrl) {
|
if (svgUrl) {
|
||||||
floorPlanSvg.src = svgUrl;
|
backgroundImage.setAttribute('href', svgUrl);
|
||||||
floorPlanSvg.hidden = false;
|
backgroundImage.setAttribute('width', String(planSize.width));
|
||||||
|
backgroundImage.setAttribute('height', String(planSize.height));
|
||||||
|
backgroundImage.setAttribute('display', 'block');
|
||||||
loadPlanDimensions(svgUrl);
|
loadPlanDimensions(svgUrl);
|
||||||
} else {
|
} else {
|
||||||
floorPlanSvg.removeAttribute('src');
|
backgroundImage.removeAttribute('href');
|
||||||
floorPlanSvg.hidden = true;
|
backgroundImage.setAttribute('display', 'none');
|
||||||
planSize.width = DEFAULT_PLAN_SIZE.width;
|
planSize.width = DEFAULT_PLAN_SIZE.width;
|
||||||
planSize.height = DEFAULT_PLAN_SIZE.height;
|
planSize.height = DEFAULT_PLAN_SIZE.height;
|
||||||
resetView();
|
resetView();
|
||||||
@@ -335,13 +344,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
filterPatchpanelBindOptions();
|
filterPatchpanelBindOptions();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (floorPlanSvg) {
|
|
||||||
floorPlanSvg.addEventListener('error', () => {
|
|
||||||
floorPlanSvg.removeAttribute('src');
|
|
||||||
floorPlanSvg.hidden = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadPlanDimensions = async (svgUrl) => {
|
const loadPlanDimensions = async (svgUrl) => {
|
||||||
if (!svgUrl) {
|
if (!svgUrl) {
|
||||||
return;
|
return;
|
||||||
@@ -365,6 +367,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
if (parts.length === 4 && parts.every((value) => Number.isFinite(value))) {
|
if (parts.length === 4 && parts.every((value) => Number.isFinite(value))) {
|
||||||
planSize.width = Math.max(1, parts[2]);
|
planSize.width = Math.max(1, parts[2]);
|
||||||
planSize.height = Math.max(1, parts[3]);
|
planSize.height = Math.max(1, parts[3]);
|
||||||
|
backgroundImage.setAttribute('width', String(planSize.width));
|
||||||
|
backgroundImage.setAttribute('height', String(planSize.height));
|
||||||
resetView();
|
resetView();
|
||||||
renderReferenceMarkers();
|
renderReferenceMarkers();
|
||||||
updateFromInputs();
|
updateFromInputs();
|
||||||
@@ -381,12 +385,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
planSize.width = DEFAULT_PLAN_SIZE.width;
|
planSize.width = DEFAULT_PLAN_SIZE.width;
|
||||||
planSize.height = DEFAULT_PLAN_SIZE.height;
|
planSize.height = DEFAULT_PLAN_SIZE.height;
|
||||||
}
|
}
|
||||||
|
backgroundImage.setAttribute('width', String(planSize.width));
|
||||||
|
backgroundImage.setAttribute('height', String(planSize.height));
|
||||||
resetView();
|
resetView();
|
||||||
renderReferenceMarkers();
|
renderReferenceMarkers();
|
||||||
updateFromInputs();
|
updateFromInputs();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
planSize.width = DEFAULT_PLAN_SIZE.width;
|
planSize.width = DEFAULT_PLAN_SIZE.width;
|
||||||
planSize.height = DEFAULT_PLAN_SIZE.height;
|
planSize.height = DEFAULT_PLAN_SIZE.height;
|
||||||
|
backgroundImage.setAttribute('width', String(planSize.width));
|
||||||
|
backgroundImage.setAttribute('height', String(planSize.height));
|
||||||
resetView();
|
resetView();
|
||||||
renderReferenceMarkers();
|
renderReferenceMarkers();
|
||||||
updateFromInputs();
|
updateFromInputs();
|
||||||
@@ -584,23 +592,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelectorAll('[data-floor-plan-zoom]').forEach((button) => {
|
|
||||||
button.addEventListener('click', () => {
|
|
||||||
const action = button.getAttribute('data-floor-plan-zoom');
|
|
||||||
if (action === 'in') {
|
|
||||||
const rect = overlay.getBoundingClientRect();
|
|
||||||
zoomAt(rect.left + (rect.width / 2), rect.top + (rect.height / 2), 0.85);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action === 'out') {
|
|
||||||
const rect = overlay.getBoundingClientRect();
|
|
||||||
zoomAt(rect.left + (rect.width / 2), rect.top + (rect.height / 2), 1.15);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resetView();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
updateOverlayViewBox();
|
updateOverlayViewBox();
|
||||||
updateFromInputs();
|
updateFromInputs();
|
||||||
filterPatchpanelBindOptions();
|
filterPatchpanelBindOptions();
|
||||||
|
|||||||
@@ -77,9 +77,6 @@ $isEndpointAllowed = static function (string $type, int $id) use ($occupiedByTyp
|
|||||||
if ($id <= 0) {
|
if ($id <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($type === 'outlet') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ($type === $portAType && $id === $portAId) {
|
if ($type === $portAType && $id === $portAId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -173,7 +170,14 @@ foreach ($outletPorts as $row) {
|
|||||||
if (!$isEndpointAllowed('outlet', $id)) {
|
if (!$isEndpointAllowed('outlet', $id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$parts = array_filter([(string)($row['floor_name'] ?? ''), (string)($row['room_name'] ?? ''), (string)$row['outlet_name'], (string)$row['name']]);
|
$portName = trim((string)($row['name'] ?? ''));
|
||||||
|
$includePortName = ($portName !== '' && strcasecmp($portName, 'Port 1') !== 0);
|
||||||
|
$parts = array_filter([
|
||||||
|
(string)($row['floor_name'] ?? ''),
|
||||||
|
(string)($row['room_name'] ?? ''),
|
||||||
|
(string)$row['outlet_name'],
|
||||||
|
$includePortName ? $portName : '',
|
||||||
|
]);
|
||||||
$endpointOptions['outlet'][] = [
|
$endpointOptions['outlet'][] = [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'label' => implode(' / ', $parts),
|
'label' => implode(' / ', $parts),
|
||||||
|
|||||||
@@ -75,25 +75,16 @@ $otherConnections = $sql->get(
|
|||||||
);
|
);
|
||||||
|
|
||||||
$endpointUsage = [];
|
$endpointUsage = [];
|
||||||
$trackUsage = static function (string $endpointType, int $endpointId, string $otherType) use (&$endpointUsage): void {
|
$trackUsage = static function (string $endpointType, int $endpointId) use (&$endpointUsage): void {
|
||||||
if ($endpointId <= 0) {
|
if ($endpointId <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isset($endpointUsage[$endpointType][$endpointId])) {
|
if (!isset($endpointUsage[$endpointType][$endpointId])) {
|
||||||
$endpointUsage[$endpointType][$endpointId] = [
|
$endpointUsage[$endpointType][$endpointId] = [
|
||||||
'total' => 0,
|
'total' => 0,
|
||||||
'patchpanel' => 0,
|
|
||||||
'other' => 0,
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$endpointUsage[$endpointType][$endpointId]['total']++;
|
$endpointUsage[$endpointType][$endpointId]['total']++;
|
||||||
if ($endpointType === 'outlet') {
|
|
||||||
if ($otherType === 'patchpanel') {
|
|
||||||
$endpointUsage[$endpointType][$endpointId]['patchpanel']++;
|
|
||||||
} else {
|
|
||||||
$endpointUsage[$endpointType][$endpointId]['other']++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach ((array)$otherConnections as $row) {
|
foreach ((array)$otherConnections as $row) {
|
||||||
@@ -102,43 +93,29 @@ foreach ((array)$otherConnections as $row) {
|
|||||||
$idA = (int)($row['port_a_id'] ?? 0);
|
$idA = (int)($row['port_a_id'] ?? 0);
|
||||||
$idB = (int)($row['port_b_id'] ?? 0);
|
$idB = (int)($row['port_b_id'] ?? 0);
|
||||||
|
|
||||||
$trackUsage($typeA, $idA, $typeB);
|
$trackUsage($typeA, $idA);
|
||||||
$trackUsage($typeB, $idB, $typeA);
|
$trackUsage($typeB, $idB);
|
||||||
}
|
}
|
||||||
|
|
||||||
$validateEndpointUsage = static function (string $endpointType, int $endpointId, string $otherType, string $label) use ($endpointUsage): ?string {
|
$validateEndpointUsage = static function (string $endpointType, int $endpointId, string $label) use ($endpointUsage): ?string {
|
||||||
if ($endpointId <= 0) {
|
if ($endpointId <= 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$stats = $endpointUsage[$endpointType][$endpointId] ?? ['total' => 0, 'patchpanel' => 0, 'other' => 0];
|
$stats = $endpointUsage[$endpointType][$endpointId] ?? ['total' => 0];
|
||||||
if ((int)$stats['total'] <= 0) {
|
if ((int)$stats['total'] <= 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($endpointType !== 'outlet') {
|
return $label . " ist bereits in Verwendung";
|
||||||
return $label . " ist bereits in Verwendung";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($otherType === 'patchpanel') {
|
|
||||||
if ((int)$stats['patchpanel'] > 0) {
|
|
||||||
return $label . " hat bereits eine Patchpanel-Verbindung";
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((int)$stats['other'] > 0) {
|
|
||||||
return $label . " hat bereits eine Endgeraete-Verbindung";
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$errorA = $validateEndpointUsage($portAType, $portAId, $portBType, 'Port an Endpunkt A');
|
$errorA = $validateEndpointUsage($portAType, $portAId, 'Port an Endpunkt A');
|
||||||
if ($errorA !== null) {
|
if ($errorA !== null) {
|
||||||
$errors[] = $errorA;
|
$errors[] = $errorA;
|
||||||
}
|
}
|
||||||
|
|
||||||
$errorB = $validateEndpointUsage($portBType, $portBId, $portAType, 'Port an Endpunkt B');
|
$errorB = $validateEndpointUsage($portBType, $portBId, 'Port an Endpunkt B');
|
||||||
if ($errorB !== null) {
|
if ($errorB !== null) {
|
||||||
$errors[] = $errorB;
|
$errors[] = $errorB;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,11 +248,6 @@ if ($type === 'outlet' && $id > 0) {
|
|||||||
<div id="panel-floor-plan-group" class="form-group" <?php echo $showPanelPlacementFields ? '' : 'hidden'; ?>>
|
<div id="panel-floor-plan-group" class="form-group" <?php echo $showPanelPlacementFields ? '' : 'hidden'; ?>>
|
||||||
<label>Stockwerkskarte</label>
|
<label>Stockwerkskarte</label>
|
||||||
<div class="floor-plan-block">
|
<div class="floor-plan-block">
|
||||||
<div class="floor-plan-toolbar">
|
|
||||||
<button type="button" class="button button-small" data-floor-plan-zoom="in">+</button>
|
|
||||||
<button type="button" class="button button-small" data-floor-plan-zoom="out">-</button>
|
|
||||||
<button type="button" class="button button-small" data-floor-plan-zoom="reset">Reset</button>
|
|
||||||
</div>
|
|
||||||
<div id="floor-plan-canvas" class="floor-plan-canvas"
|
<div id="floor-plan-canvas" class="floor-plan-canvas"
|
||||||
data-marker-width="<?php echo $markerWidth; ?>"
|
data-marker-width="<?php echo $markerWidth; ?>"
|
||||||
data-marker-height="<?php echo $markerHeight; ?>"
|
data-marker-height="<?php echo $markerHeight; ?>"
|
||||||
@@ -262,10 +257,9 @@ if ($type === 'outlet' && $id > 0) {
|
|||||||
data-active-id="<?php echo (int)($panel['id'] ?? 0); ?>"
|
data-active-id="<?php echo (int)($panel['id'] ?? 0); ?>"
|
||||||
data-reference-panels="<?php echo htmlspecialchars(json_encode($mapPatchPanels, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>"
|
data-reference-panels="<?php echo htmlspecialchars(json_encode($mapPatchPanels, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>"
|
||||||
data-reference-outlets="<?php echo htmlspecialchars(json_encode($mapOutlets, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>">
|
data-reference-outlets="<?php echo htmlspecialchars(json_encode($mapOutlets, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
<img id="floor-plan-svg" class="floor-plan-svg" alt="Stockwerksplan">
|
|
||||||
<svg id="floor-plan-overlay" class="floor-plan-overlay" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid meet" aria-hidden="true"></svg>
|
<svg id="floor-plan-overlay" class="floor-plan-overlay" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid meet" aria-hidden="true"></svg>
|
||||||
</div>
|
</div>
|
||||||
<p class="floor-plan-hint">Nur das aktuell bearbeitete Patchpanel ist verschiebbar. Andere Objekte werden als Referenz halbtransparent angezeigt. Neue Objekte starten bei Position 30 x 30. Zoom per Mausrad, verschieben mit Shift + Drag.</p>
|
<p class="floor-plan-hint">Nur das aktuell bearbeitete Patchpanel ist verschiebbar. Andere Objekte werden als Referenz halbtransparent angezeigt. Neue Objekte starten bei Position 30 x 30. Zoom mit Mausrad, verschieben mit Shift + Drag.</p>
|
||||||
<p class="floor-plan-position">Koordinate: <span id="floor-plan-position"></span></p>
|
<p class="floor-plan-position">Koordinate: <span id="floor-plan-position"></span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -350,11 +344,6 @@ if ($type === 'outlet' && $id > 0) {
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Stockwerkskarte</label>
|
<label>Stockwerkskarte</label>
|
||||||
<div class="floor-plan-block">
|
<div class="floor-plan-block">
|
||||||
<div class="floor-plan-toolbar">
|
|
||||||
<button type="button" class="button button-small" data-floor-plan-zoom="in">+</button>
|
|
||||||
<button type="button" class="button button-small" data-floor-plan-zoom="out">-</button>
|
|
||||||
<button type="button" class="button button-small" data-floor-plan-zoom="reset">Reset</button>
|
|
||||||
</div>
|
|
||||||
<div id="floor-plan-canvas" class="floor-plan-canvas"
|
<div id="floor-plan-canvas" class="floor-plan-canvas"
|
||||||
data-marker-width="<?php echo $markerWidth; ?>"
|
data-marker-width="<?php echo $markerWidth; ?>"
|
||||||
data-marker-height="<?php echo $markerHeight; ?>"
|
data-marker-height="<?php echo $markerHeight; ?>"
|
||||||
@@ -364,10 +353,9 @@ if ($type === 'outlet' && $id > 0) {
|
|||||||
data-active-id="<?php echo (int)($outlet['id'] ?? 0); ?>"
|
data-active-id="<?php echo (int)($outlet['id'] ?? 0); ?>"
|
||||||
data-reference-panels="<?php echo htmlspecialchars(json_encode($mapPatchPanels, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>"
|
data-reference-panels="<?php echo htmlspecialchars(json_encode($mapPatchPanels, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>"
|
||||||
data-reference-outlets="<?php echo htmlspecialchars(json_encode($mapOutlets, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>">
|
data-reference-outlets="<?php echo htmlspecialchars(json_encode($mapOutlets, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8'); ?>">
|
||||||
<img id="floor-plan-svg" class="floor-plan-svg" alt="Stockwerksplan">
|
|
||||||
<svg id="floor-plan-overlay" class="floor-plan-overlay" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid meet" aria-hidden="true"></svg>
|
<svg id="floor-plan-overlay" class="floor-plan-overlay" viewBox="0 0 1 1" preserveAspectRatio="xMidYMid meet" aria-hidden="true"></svg>
|
||||||
</div>
|
</div>
|
||||||
<p class="floor-plan-hint">Nur die aktuell bearbeitete Wandbuchse ist verschiebbar. Blau = Patchpanel, Gruen = Dosen-Referenz, Orange = gewaehlter Raum. Netzwerkdosen sind immer 10 x 10. Zoom per Mausrad, verschieben mit Shift + Drag.</p>
|
<p class="floor-plan-hint">Nur die aktuell bearbeitete Wandbuchse ist verschiebbar. Blau = Patchpanel, Gruen = Dosen-Referenz, Orange = gewaehlter Raum. Netzwerkdosen sind immer 10 x 10. Zoom mit Mausrad, verschieben mit Shift + Drag.</p>
|
||||||
<p class="floor-plan-position">Koordinate: <span id="floor-plan-position"></span></p>
|
<p class="floor-plan-position">Koordinate: <span id="floor-plan-position"></span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user