feat(schematic): Terminal-Farben, Leitungen hinter Blöcken, Zeichenmodus v11.0
Terminal-Farben nach Verbindung: - Terminals zeigen Farbe der angeschlossenen Leitung - Grau = keine Verbindung, farbig = Leitung angeschlossen - Neue Hilfsfunktion getTerminalConnectionColor() Leitungen hinter Blöcken: - Layer-Reihenfolge geändert: connections vor blocks - Professionelleres Erscheinungsbild Zeichenmodus-Verbesserungen: - Rechtsklick/Escape bricht nur Linie ab, nicht Modus - Crosshair-Cursor überall im SVG während Zeichenmodus - 30px Hit-Area für bessere Klickbarkeit Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
4540b8c595
commit
6b3b6d7e95
134 changed files with 312 additions and 39 deletions
0
COPYING
Executable file → Normal file
0
COPYING
Executable file → Normal file
34
ChangeLog.md
34
ChangeLog.md
|
|
@ -1,5 +1,39 @@
|
||||||
# CHANGELOG MODULE KUNDENKARTE FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)
|
# CHANGELOG MODULE KUNDENKARTE FOR [DOLIBARR ERP CRM](https://www.dolibarr.org)
|
||||||
|
|
||||||
|
## 11.0 (2026-03)
|
||||||
|
|
||||||
|
### Neue Features
|
||||||
|
|
||||||
|
- **Terminal-Farben nach Verbindung**: Terminals zeigen die Farbe der angeschlossenen Leitung
|
||||||
|
- Grau = keine Verbindung, farbig = Leitung angeschlossen
|
||||||
|
- Farbe entspricht dem Leitungstyp (L1=braun, L2=schwarz, L3=grau, N=blau, PE=gruen)
|
||||||
|
- Neue Hilfsfunktion `getTerminalConnectionColor()`
|
||||||
|
|
||||||
|
- **Leitungen hinter Bloecken**: Wires werden nun hinter den Equipment-Bloecken gerendert
|
||||||
|
- Layer-Reihenfolge geaendert: connections-layer vor blocks-layer
|
||||||
|
- Leitungen "verschwinden" hinter Bloecken und kommen auf der anderen Seite wieder raus
|
||||||
|
- Professionelleres Erscheinungsbild wie in echten Schaltplan-Editoren
|
||||||
|
|
||||||
|
### Verbesserungen
|
||||||
|
|
||||||
|
- **Zeichenmodus-Verhalten**: Konsistentes Verhalten im manuellen Zeichenmodus
|
||||||
|
- Rechtsklick bricht nur aktuelle Linie ab, nicht den Zeichenmodus
|
||||||
|
- Escape-Taste verhaelt sich identisch (Linie abbrechen, Modus bleibt aktiv)
|
||||||
|
- Crosshair-Cursor ueberall im SVG waehrend Zeichenmodus (nicht nur auf Terminals)
|
||||||
|
- Keine Unterbrechung mehr beim Klicken auf leere Flaechen
|
||||||
|
|
||||||
|
- **Terminal Hit-Area**: Verbesserte Klickbarkeit der Terminals
|
||||||
|
- 30px Radius fuer einfacheres Anklicken
|
||||||
|
- `pointer-events:all` fuer zuverlaessige Event-Erfassung
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
|
||||||
|
- Cursor zeigte nicht ueberall Crosshair im Zeichenmodus
|
||||||
|
- Zeichenmodus wurde bei Rechtsklick/Escape komplett beendet statt nur Linie abzubrechen
|
||||||
|
- Junction-Verbindungen (Terminal zu Leitung) werden korrekt gerendert
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 8.6 (2026-03)
|
## 8.6 (2026-03)
|
||||||
|
|
||||||
### Neue Features
|
### Neue Features
|
||||||
|
|
|
||||||
0
README.md
Executable file → Normal file
0
README.md
Executable file → Normal file
0
admin/about.php
Executable file → Normal file
0
admin/about.php
Executable file → Normal file
0
admin/anlage_systems.php
Executable file → Normal file
0
admin/anlage_systems.php
Executable file → Normal file
0
admin/backup.php
Executable file → Normal file
0
admin/backup.php
Executable file → Normal file
0
admin/busbar_types.php
Executable file → Normal file
0
admin/busbar_types.php
Executable file → Normal file
0
admin/medium_types.php
Executable file → Normal file
0
admin/medium_types.php
Executable file → Normal file
0
ajax/anlage.php
Executable file → Normal file
0
ajax/anlage.php
Executable file → Normal file
0
ajax/anlage_connection.php
Executable file → Normal file
0
ajax/anlage_connection.php
Executable file → Normal file
0
ajax/anlage_docs.php
Executable file → Normal file
0
ajax/anlage_docs.php
Executable file → Normal file
0
ajax/anlage_images.php
Executable file → Normal file
0
ajax/anlage_images.php
Executable file → Normal file
0
ajax/anlage_tooltip.php
Executable file → Normal file
0
ajax/anlage_tooltip.php
Executable file → Normal file
0
ajax/audit_log.php
Executable file → Normal file
0
ajax/audit_log.php
Executable file → Normal file
0
ajax/bom_generator.php
Executable file → Normal file
0
ajax/bom_generator.php
Executable file → Normal file
0
ajax/building_types.php
Executable file → Normal file
0
ajax/building_types.php
Executable file → Normal file
0
ajax/equipment.php
Executable file → Normal file
0
ajax/equipment.php
Executable file → Normal file
0
ajax/equipment_carrier.php
Executable file → Normal file
0
ajax/equipment_carrier.php
Executable file → Normal file
9
ajax/equipment_connection.php
Executable file → Normal file
9
ajax/equipment_connection.php
Executable file → Normal file
|
|
@ -44,8 +44,11 @@ switch ($action) {
|
||||||
'id' => $connection->id,
|
'id' => $connection->id,
|
||||||
'fk_source' => $connection->fk_source,
|
'fk_source' => $connection->fk_source,
|
||||||
'source_terminal' => $connection->source_terminal,
|
'source_terminal' => $connection->source_terminal,
|
||||||
|
'source_terminal_id' => $connection->source_terminal_id,
|
||||||
|
'bundled_terminals' => $connection->bundled_terminals,
|
||||||
'fk_target' => $connection->fk_target,
|
'fk_target' => $connection->fk_target,
|
||||||
'target_terminal' => $connection->target_terminal,
|
'target_terminal' => $connection->target_terminal,
|
||||||
|
'target_terminal_id' => $connection->target_terminal_id,
|
||||||
'connection_type' => $connection->connection_type,
|
'connection_type' => $connection->connection_type,
|
||||||
'color' => $connection->color,
|
'color' => $connection->color,
|
||||||
'output_label' => $connection->output_label,
|
'output_label' => $connection->output_label,
|
||||||
|
|
@ -77,11 +80,14 @@ switch ($action) {
|
||||||
'id' => $c->id,
|
'id' => $c->id,
|
||||||
'fk_source' => $c->fk_source,
|
'fk_source' => $c->fk_source,
|
||||||
'source_terminal' => $c->source_terminal,
|
'source_terminal' => $c->source_terminal,
|
||||||
|
'source_terminal_id' => $c->source_terminal_id,
|
||||||
|
'bundled_terminals' => $c->bundled_terminals,
|
||||||
'source_label' => $c->source_label,
|
'source_label' => $c->source_label,
|
||||||
'source_pos' => $c->source_pos,
|
'source_pos' => $c->source_pos,
|
||||||
'source_width' => $c->source_width,
|
'source_width' => $c->source_width,
|
||||||
'fk_target' => $c->fk_target,
|
'fk_target' => $c->fk_target,
|
||||||
'target_terminal' => $c->target_terminal,
|
'target_terminal' => $c->target_terminal,
|
||||||
|
'target_terminal_id' => $c->target_terminal_id,
|
||||||
'target_label' => $c->target_label,
|
'target_label' => $c->target_label,
|
||||||
'target_pos' => $c->target_pos,
|
'target_pos' => $c->target_pos,
|
||||||
'connection_type' => $c->connection_type,
|
'connection_type' => $c->connection_type,
|
||||||
|
|
@ -154,6 +160,7 @@ switch ($action) {
|
||||||
$connection->fk_carrier = $carrierId;
|
$connection->fk_carrier = $carrierId;
|
||||||
$connection->position_y = GETPOSTINT('position_y');
|
$connection->position_y = GETPOSTINT('position_y');
|
||||||
$connection->path_data = GETPOST('path_data', 'nohtml');
|
$connection->path_data = GETPOST('path_data', 'nohtml');
|
||||||
|
$connection->bundled_terminals = GETPOST('bundled_terminals', 'alphanohtml');
|
||||||
|
|
||||||
$result = $connection->create($user);
|
$result = $connection->create($user);
|
||||||
if ($result > 0) {
|
if ($result > 0) {
|
||||||
|
|
@ -188,6 +195,7 @@ switch ($action) {
|
||||||
if (GETPOSTISSET('excluded_te')) $connection->excluded_te = GETPOST('excluded_te', 'alphanohtml');
|
if (GETPOSTISSET('excluded_te')) $connection->excluded_te = GETPOST('excluded_te', 'alphanohtml');
|
||||||
if (GETPOSTISSET('position_y')) $connection->position_y = GETPOSTINT('position_y');
|
if (GETPOSTISSET('position_y')) $connection->position_y = GETPOSTINT('position_y');
|
||||||
if (GETPOSTISSET('path_data')) $connection->path_data = GETPOST('path_data', 'nohtml');
|
if (GETPOSTISSET('path_data')) $connection->path_data = GETPOST('path_data', 'nohtml');
|
||||||
|
if (GETPOSTISSET('bundled_terminals')) $connection->bundled_terminals = GETPOST('bundled_terminals', 'alphanohtml');
|
||||||
|
|
||||||
$result = $connection->update($user);
|
$result = $connection->update($user);
|
||||||
if ($result > 0) {
|
if ($result > 0) {
|
||||||
|
|
@ -341,6 +349,7 @@ switch ($action) {
|
||||||
'fk_source' => $obj->fk_source,
|
'fk_source' => $obj->fk_source,
|
||||||
'source_terminal' => $obj->source_terminal,
|
'source_terminal' => $obj->source_terminal,
|
||||||
'source_terminal_id' => $obj->source_terminal_id,
|
'source_terminal_id' => $obj->source_terminal_id,
|
||||||
|
'bundled_terminals' => isset($obj->bundled_terminals) ? $obj->bundled_terminals : null,
|
||||||
'source_label' => $obj->source_label,
|
'source_label' => $obj->source_label,
|
||||||
'source_pos' => $obj->source_pos,
|
'source_pos' => $obj->source_pos,
|
||||||
'source_width' => $obj->source_width,
|
'source_width' => $obj->source_width,
|
||||||
|
|
|
||||||
0
ajax/equipment_panel.php
Executable file → Normal file
0
ajax/equipment_panel.php
Executable file → Normal file
0
ajax/equipment_type_block_image.php
Executable file → Normal file
0
ajax/equipment_type_block_image.php
Executable file → Normal file
0
ajax/equipment_type_fields.php
Executable file → Normal file
0
ajax/equipment_type_fields.php
Executable file → Normal file
0
ajax/equipment_type_icon.php
Executable file → Normal file
0
ajax/equipment_type_icon.php
Executable file → Normal file
0
ajax/export_schematic_pdf.php
Executable file → Normal file
0
ajax/export_schematic_pdf.php
Executable file → Normal file
0
ajax/export_tree_pdf.php
Executable file → Normal file
0
ajax/export_tree_pdf.php
Executable file → Normal file
0
ajax/favorite_update.php
Executable file → Normal file
0
ajax/favorite_update.php
Executable file → Normal file
0
ajax/field_autocomplete.php
Executable file → Normal file
0
ajax/field_autocomplete.php
Executable file → Normal file
0
ajax/file_preview.php
Executable file → Normal file
0
ajax/file_preview.php
Executable file → Normal file
0
ajax/graph_data.php
Executable file → Normal file
0
ajax/graph_data.php
Executable file → Normal file
0
ajax/graph_save_positions.php
Executable file → Normal file
0
ajax/graph_save_positions.php
Executable file → Normal file
0
ajax/icon_upload.php
Executable file → Normal file
0
ajax/icon_upload.php
Executable file → Normal file
0
ajax/medium_types.php
Executable file → Normal file
0
ajax/medium_types.php
Executable file → Normal file
0
ajax/pwa_api.php
Executable file → Normal file
0
ajax/pwa_api.php
Executable file → Normal file
0
ajax/tree_config.php
Executable file → Normal file
0
ajax/tree_config.php
Executable file → Normal file
0
ajax/type_fields.php
Executable file → Normal file
0
ajax/type_fields.php
Executable file → Normal file
0
anlage_connection.php
Executable file → Normal file
0
anlage_connection.php
Executable file → Normal file
0
build/buildzip.php
Executable file → Normal file
0
build/buildzip.php
Executable file → Normal file
0
build/makepack-kundenkarte.conf
Executable file → Normal file
0
build/makepack-kundenkarte.conf
Executable file → Normal file
0
class/anlage.class.php
Executable file → Normal file
0
class/anlage.class.php
Executable file → Normal file
0
class/anlagebackup.class.php
Executable file → Normal file
0
class/anlagebackup.class.php
Executable file → Normal file
0
class/anlageconnection.class.php
Executable file → Normal file
0
class/anlageconnection.class.php
Executable file → Normal file
0
class/anlagefile.class.php
Executable file → Normal file
0
class/anlagefile.class.php
Executable file → Normal file
0
class/auditlog.class.php
Executable file → Normal file
0
class/auditlog.class.php
Executable file → Normal file
0
class/busbartype.class.php
Executable file → Normal file
0
class/busbartype.class.php
Executable file → Normal file
0
class/equipment.class.php
Executable file → Normal file
0
class/equipment.class.php
Executable file → Normal file
0
class/equipmentcarrier.class.php
Executable file → Normal file
0
class/equipmentcarrier.class.php
Executable file → Normal file
0
class/equipmentconnection.class.php
Executable file → Normal file
0
class/equipmentconnection.class.php
Executable file → Normal file
0
class/equipmentpanel.class.php
Executable file → Normal file
0
class/equipmentpanel.class.php
Executable file → Normal file
0
class/equipmenttype.class.php
Executable file → Normal file
0
class/equipmenttype.class.php
Executable file → Normal file
0
class/favoriteproduct.class.php
Executable file → Normal file
0
class/favoriteproduct.class.php
Executable file → Normal file
0
class/mediumtype.class.php
Executable file → Normal file
0
class/mediumtype.class.php
Executable file → Normal file
0
class/terminalbridge.class.php
Executable file → Normal file
0
class/terminalbridge.class.php
Executable file → Normal file
2
core/modules/modKundenKarte.class.php
Executable file → Normal file
2
core/modules/modKundenKarte.class.php
Executable file → Normal file
|
|
@ -76,7 +76,7 @@ class modKundenKarte extends DolibarrModules
|
||||||
$this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@kundenkarte'
|
$this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@kundenkarte'
|
||||||
|
|
||||||
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z'
|
// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z'
|
||||||
$this->version = '8.6';
|
$this->version = '9.6';
|
||||||
// Url to the file with your last numberversion of this module
|
// Url to the file with your last numberversion of this module
|
||||||
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';
|
//$this->url_last_version = 'http://www.example.com/versionmodule.txt';
|
||||||
|
|
||||||
|
|
|
||||||
30
css/kundenkarte.css
Executable file → Normal file
30
css/kundenkarte.css
Executable file → Normal file
|
|
@ -2119,6 +2119,13 @@ body.kundenkarte-drag-active * {
|
||||||
margin-top: 20px !important;
|
margin-top: 20px !important;
|
||||||
max-width: 100% !important;
|
max-width: 100% !important;
|
||||||
overflow-x: auto !important;
|
overflow-x: auto !important;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prevent gap between header and message */
|
||||||
|
.schematic-editor-wrapper > * {
|
||||||
|
flex-shrink: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prevent Schematic Editor from breaking Dolibarr layout */
|
/* Prevent Schematic Editor from breaking Dolibarr layout */
|
||||||
|
|
@ -2135,6 +2142,17 @@ body.kundenkarte-drag-active * {
|
||||||
background: #252525 !important;
|
background: #252525 !important;
|
||||||
border: 1px solid #333 !important;
|
border: 1px solid #333 !important;
|
||||||
border-radius: 4px 4px 0 0 !important;
|
border-radius: 4px 4px 0 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
min-height: 50px !important;
|
||||||
|
flex-wrap: wrap !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.schematic-editor-actions {
|
||||||
|
display: flex !important;
|
||||||
|
flex-wrap: wrap !important;
|
||||||
|
gap: 10px !important;
|
||||||
|
align-items: center !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.schematic-editor-toggle {
|
.schematic-editor-toggle {
|
||||||
|
|
@ -2163,6 +2181,7 @@ body.kundenkarte-drag-active * {
|
||||||
min-height: 300px !important;
|
min-height: 300px !important;
|
||||||
max-width: 100% !important;
|
max-width: 100% !important;
|
||||||
box-sizing: border-box !important;
|
box-sizing: border-box !important;
|
||||||
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.schematic-editor-canvas.expanded {
|
.schematic-editor-canvas.expanded {
|
||||||
|
|
@ -2214,13 +2233,19 @@ body.kundenkarte-drag-active * {
|
||||||
transition: filter 0.2s ease !important;
|
transition: filter 0.2s ease !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terminals */
|
/* Terminals - hitarea captures all events */
|
||||||
.schematic-terminal {
|
.schematic-terminal {
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.schematic-terminal-hitarea {
|
||||||
cursor: crosshair !important;
|
cursor: crosshair !important;
|
||||||
|
pointer-events: all !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.schematic-terminal-circle {
|
.schematic-terminal-circle {
|
||||||
transition: all 0.2s ease !important;
|
transition: all 0.2s ease !important;
|
||||||
|
pointer-events: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.schematic-terminal:hover .schematic-terminal-circle {
|
.schematic-terminal:hover .schematic-terminal-circle {
|
||||||
|
|
@ -2260,7 +2285,7 @@ body.kundenkarte-drag-active * {
|
||||||
/* Messages - Fixed height status bar */
|
/* Messages - Fixed height status bar */
|
||||||
.schematic-message {
|
.schematic-message {
|
||||||
padding: 6px 15px !important;
|
padding: 6px 15px !important;
|
||||||
margin-bottom: 0 !important;
|
margin: 0 !important;
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
font-size: 12px !important;
|
font-size: 12px !important;
|
||||||
height: 28px !important;
|
height: 28px !important;
|
||||||
|
|
@ -2275,6 +2300,7 @@ body.kundenkarte-drag-active * {
|
||||||
border: 1px solid #3498db !important;
|
border: 1px solid #3498db !important;
|
||||||
border-top: none !important;
|
border-top: none !important;
|
||||||
border-bottom: none !important;
|
border-bottom: none !important;
|
||||||
|
display: block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.schematic-message.info {
|
.schematic-message.info {
|
||||||
|
|
|
||||||
0
css/kundenkarte_cytoscape.css
Executable file → Normal file
0
css/kundenkarte_cytoscape.css
Executable file → Normal file
15
css/pwa.css
Executable file → Normal file
15
css/pwa.css
Executable file → Normal file
|
|
@ -1144,6 +1144,21 @@ body {
|
||||||
stroke-linejoin: round;
|
stroke-linejoin: round;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Wire Toggle Button */
|
||||||
|
#btn-toggle-wires {
|
||||||
|
opacity: 0.5;
|
||||||
|
transition: opacity 0.2s, background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#btn-toggle-wires.active {
|
||||||
|
opacity: 1;
|
||||||
|
background: rgba(173, 140, 79, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#btn-toggle-wires svg {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
/* Grid-Rows: 1=Labels oben, 2=Terminals oben, 3=Equipment, 4=Terminals unten, 5=Labels unten */
|
/* Grid-Rows: 1=Labels oben, 2=Terminals oben, 3=Equipment, 4=Terminals unten, 5=Labels unten */
|
||||||
/* Add Button in Carrier (letzte Spalte, Zeile 2) */
|
/* Add Button in Carrier (letzte Spalte, Zeile 2) */
|
||||||
.btn-add-equipment {
|
.btn-add-equipment {
|
||||||
|
|
|
||||||
0
img/README.md
Executable file → Normal file
0
img/README.md
Executable file → Normal file
0
js/cose-base.js
Executable file → Normal file
0
js/cose-base.js
Executable file → Normal file
0
js/cytoscape-cose-bilkent.js
Executable file → Normal file
0
js/cytoscape-cose-bilkent.js
Executable file → Normal file
0
js/cytoscape-dagre.js
Executable file → Normal file
0
js/cytoscape-dagre.js
Executable file → Normal file
0
js/cytoscape.min.js
vendored
Executable file → Normal file
0
js/cytoscape.min.js
vendored
Executable file → Normal file
0
js/dagre.min.js
vendored
Executable file → Normal file
0
js/dagre.min.js
vendored
Executable file → Normal file
|
|
@ -5276,12 +5276,39 @@
|
||||||
return '#f1c40f'; // Default yellow
|
return '#f1c40f'; // Default yellow
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Get connection color for a specific terminal (if connected)
|
||||||
|
getTerminalConnectionColor: function(equipmentId, terminalId) {
|
||||||
|
var eqId = String(equipmentId);
|
||||||
|
var termId = String(terminalId);
|
||||||
|
|
||||||
|
if (!this.connections || this.connections.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find connection where this terminal is source or target
|
||||||
|
var conn = this.connections.find(function(c) {
|
||||||
|
var isSource = String(c.fk_source) === eqId && String(c.source_terminal_id) === termId;
|
||||||
|
var isTarget = String(c.fk_target) === eqId && String(c.target_terminal_id) === termId;
|
||||||
|
return isSource || isTarget;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (conn) {
|
||||||
|
// Return explicit color or derive from connection_type
|
||||||
|
if (conn.color) return conn.color;
|
||||||
|
if (conn.connection_type) return this.getWireColor(conn.connection_type);
|
||||||
|
// Fallback: return a default wire color
|
||||||
|
return '#f1c40f'; // Yellow as default connected color
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // No connection found
|
||||||
|
},
|
||||||
|
|
||||||
// Get terminal shape SVG based on style setting
|
// Get terminal shape SVG based on style setting
|
||||||
getTerminalShape: function(radius, fillColor) {
|
getTerminalShape: function(radius, fillColor) {
|
||||||
var style = this.displaySettings.terminalStyle || 'circle';
|
var style = this.displaySettings.terminalStyle || 'circle';
|
||||||
// Add invisible hit area (larger than visible terminal) for easier clicking
|
// Add invisible hit area (larger than visible terminal) for easier clicking
|
||||||
var hitAreaRadius = radius * 1.4; // 11px hit area - prevents overlap on dense terminals
|
var hitAreaRadius = 30; // 30px hit area for easy clicking
|
||||||
var hitArea = '<circle r="' + hitAreaRadius + '" fill="transparent" class="schematic-terminal-hitarea" style="cursor:inherit;"/>';
|
var hitArea = '<circle r="' + hitAreaRadius + '" fill="rgba(0,0,0,0.001)" class="schematic-terminal-hitarea" style="pointer-events:all;"/>';
|
||||||
|
|
||||||
switch (style) {
|
switch (style) {
|
||||||
case 'ring':
|
case 'ring':
|
||||||
|
|
@ -5473,6 +5500,8 @@
|
||||||
|
|
||||||
// Block drag - track if dragged to distinguish from click
|
// Block drag - track if dragged to distinguish from click
|
||||||
$(document).off('mousedown.blockDrag').on('mousedown.blockDrag', '.schematic-block', function(e) {
|
$(document).off('mousedown.blockDrag').on('mousedown.blockDrag', '.schematic-block', function(e) {
|
||||||
|
// Im Zeichenmodus kein Block-Drag
|
||||||
|
if (self.wireDrawMode) return;
|
||||||
if ($(e.target).hasClass('schematic-terminal')) return;
|
if ($(e.target).hasClass('schematic-terminal')) return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
self.blockDragStartPos = { x: e.clientX, y: e.clientY };
|
self.blockDragStartPos = { x: e.clientX, y: e.clientY };
|
||||||
|
|
@ -5621,15 +5650,16 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Escape - Close all popups, cancel wire draw mode
|
// Escape - Close all popups, cancel current wire (NOT exit draw mode)
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
// Close all popups
|
// Close all popups
|
||||||
$('.schematic-equipment-popup, .schematic-carrier-popup, .schematic-connection-popup, .schematic-busbar-popup, .schematic-bridge-popup').remove();
|
$('.schematic-equipment-popup, .schematic-carrier-popup, .schematic-connection-popup, .schematic-busbar-popup, .schematic-bridge-popup').remove();
|
||||||
|
|
||||||
// Cancel wire draw mode
|
// Cancel current wire drawing only (keep draw mode active)
|
||||||
if (self.wireDrawMode) {
|
if (self.wireDrawMode && (self.wireDrawSourceEq || self.wireDrawFromJunction)) {
|
||||||
self.cancelWireDraw();
|
self.cleanupWireDrawState(true);
|
||||||
|
self.showMessage('Leitung abgebrochen - weiter zeichnen', 'info');
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -5859,10 +5889,19 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Terminal right-click - show output/cable dialog
|
// Terminal right-click - show output/cable dialog (not in wire draw mode)
|
||||||
$(document).off('contextmenu.terminal').on('contextmenu.terminal', '.schematic-terminal', function(e) {
|
$(document).off('contextmenu.terminal').on('contextmenu.terminal', '.schematic-terminal', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
// Im Zeichenmodus: Rechtsklick bricht nur aktuelle Leitung ab, Modus bleibt
|
||||||
|
if (self.wireDrawMode) {
|
||||||
|
if (self.wireDrawSourceEq) {
|
||||||
|
// Aktuelle Zeichnung abbrechen, Modus bleibt
|
||||||
|
self.cleanupWireDrawState(true);
|
||||||
|
self.showMessage('Leitung abgebrochen - weiter zeichnen', 'info');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
var $terminal = $(this);
|
var $terminal = $(this);
|
||||||
var eqId = $terminal.data('equipment-id');
|
var eqId = $terminal.data('equipment-id');
|
||||||
var termId = $terminal.data('terminal-id');
|
var termId = $terminal.data('terminal-id');
|
||||||
|
|
@ -5920,20 +5959,24 @@
|
||||||
self.updateWirePreviewCursor(snapped.x, snapped.y);
|
self.updateWirePreviewCursor(snapped.x, snapped.y);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Right-click to cancel wire drawing completely
|
// Right-click to cancel current wire drawing (NOT exit draw mode)
|
||||||
$(document).off('contextmenu.wireDraw').on('contextmenu.wireDraw', '.schematic-editor-canvas svg', function(e) {
|
$(document).off('contextmenu.wireDraw').on('contextmenu.wireDraw', '.schematic-editor-canvas svg', function(e) {
|
||||||
if (!self.wireDrawMode) return;
|
if (!self.wireDrawMode) return;
|
||||||
|
// Skip if click was on terminal (handled by terminal handler)
|
||||||
|
if ($(e.target).closest('.schematic-terminal').length) return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (self.wireDrawSourceEq || self.wireDrawFromJunction) {
|
if (self.wireDrawSourceEq || self.wireDrawFromJunction) {
|
||||||
// Cancel entire drawing (from terminal or junction)
|
// Cancel current line, keep draw mode active
|
||||||
self.cancelWireDrawing();
|
self.cleanupWireDrawState(true);
|
||||||
|
self.showMessage('Leitung abgebrochen - weiter zeichnen', 'info');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Escape to cancel wire drawing
|
// Escape to cancel current wire (NOT exit draw mode)
|
||||||
$(document).off('keydown.wireDraw').on('keydown.wireDraw', function(e) {
|
$(document).off('keydown.wireDraw').on('keydown.wireDraw', function(e) {
|
||||||
if (e.key === 'Escape' && self.wireDrawMode && (self.wireDrawSourceEq || self.wireDrawFromJunction)) {
|
if (e.key === 'Escape' && self.wireDrawMode && (self.wireDrawSourceEq || self.wireDrawFromJunction)) {
|
||||||
self.cancelWireDrawing();
|
self.cleanupWireDrawState(true);
|
||||||
|
self.showMessage('Leitung abgebrochen - weiter zeichnen', 'info');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -6699,10 +6742,11 @@
|
||||||
svg += '<rect width="100%" height="100%" fill="url(#grid)"/>';
|
svg += '<rect width="100%" height="100%" fill="url(#grid)"/>';
|
||||||
|
|
||||||
// Layers (order matters: back to front)
|
// Layers (order matters: back to front)
|
||||||
|
// Connections BEHIND blocks so wires "go through" blocks visually
|
||||||
svg += '<g class="schematic-rails-layer"></g>';
|
svg += '<g class="schematic-rails-layer"></g>';
|
||||||
|
svg += '<g class="schematic-connections-layer"></g>'; // Wires behind blocks
|
||||||
svg += '<g class="schematic-blocks-layer"></g>';
|
svg += '<g class="schematic-blocks-layer"></g>';
|
||||||
svg += '<g class="schematic-busbars-layer"></g>'; // Distribution busbars (Phasenschienen)
|
svg += '<g class="schematic-busbars-layer"></g>'; // Distribution busbars (Phasenschienen)
|
||||||
svg += '<g class="schematic-connections-layer"></g>';
|
|
||||||
svg += '<g class="schematic-terminals-layer"></g>';
|
svg += '<g class="schematic-terminals-layer"></g>';
|
||||||
|
|
||||||
// Connection preview line
|
// Connection preview line
|
||||||
|
|
@ -7064,7 +7108,7 @@
|
||||||
|
|
||||||
// Top terminals - im TE-Raster platziert (hide if busbar covers this equipment or terminal_position)
|
// Top terminals - im TE-Raster platziert (hide if busbar covers this equipment or terminal_position)
|
||||||
// Now supports stacked terminals with 'row' property (for Reihenklemmen)
|
// Now supports stacked terminals with 'row' property (for Reihenklemmen)
|
||||||
var terminalColor = '#666'; // Grau wie die Hutschienen
|
var defaultTerminalColor = '#666'; // Grau wie die Hutschienen (wenn keine Verbindung)
|
||||||
var terminalSpacing = 14; // Vertical spacing between stacked terminals
|
var terminalSpacing = 14; // Vertical spacing between stacked terminals
|
||||||
|
|
||||||
if (showTopTerminals) {
|
if (showTopTerminals) {
|
||||||
|
|
@ -7085,6 +7129,9 @@
|
||||||
var row = term.row !== undefined ? term.row : rowIdx;
|
var row = term.row !== undefined ? term.row : rowIdx;
|
||||||
var ty = y - 7 - (row * terminalSpacing);
|
var ty = y - 7 - (row * terminalSpacing);
|
||||||
|
|
||||||
|
// Get connection color for this terminal (or default gray)
|
||||||
|
var terminalColor = self.getTerminalConnectionColor(eq.id, term.id) || defaultTerminalColor;
|
||||||
|
|
||||||
terminalHtml += '<g class="schematic-terminal" ';
|
terminalHtml += '<g class="schematic-terminal" ';
|
||||||
terminalHtml += 'data-equipment-id="' + eq.id + '" data-terminal-id="' + term.id + '" ';
|
terminalHtml += 'data-equipment-id="' + eq.id + '" data-terminal-id="' + term.id + '" ';
|
||||||
terminalHtml += 'transform="translate(' + tx + ',' + ty + ')">';
|
terminalHtml += 'transform="translate(' + tx + ',' + ty + ')">';
|
||||||
|
|
@ -7097,12 +7144,12 @@
|
||||||
|
|
||||||
if (colTerminals.length > 1) {
|
if (colTerminals.length > 1) {
|
||||||
// Stacked: place label to the left of the terminal
|
// Stacked: place label to the left of the terminal
|
||||||
terminalHtml += '<rect x="' + (-labelWidth - 8) + '" y="-7" width="' + labelWidth + '" height="14" rx="3" fill="rgba(0,0,0,0.85)"/>';
|
terminalHtml += '<rect x="' + (-labelWidth - 8) + '" y="-7" width="' + labelWidth + '" height="14" rx="3" fill="rgba(0,0,0,0.85)" style="pointer-events:none;"/>';
|
||||||
terminalHtml += '<text x="' + (-labelWidth/2 - 8) + '" y="3" text-anchor="middle" fill="#fff" font-size="9" font-weight="bold">' + labelText + '</text>';
|
terminalHtml += '<text x="' + (-labelWidth/2 - 8) + '" y="3" text-anchor="middle" fill="#fff" font-size="9" font-weight="bold" style="pointer-events:none;">' + labelText + '</text>';
|
||||||
} else {
|
} else {
|
||||||
// Single: place label below in block
|
// Single: place label below in block
|
||||||
terminalHtml += '<rect x="' + (-labelWidth/2) + '" y="14" width="' + labelWidth + '" height="14" rx="3" fill="rgba(0,0,0,0.85)"/>';
|
terminalHtml += '<rect x="' + (-labelWidth/2) + '" y="14" width="' + labelWidth + '" height="14" rx="3" fill="rgba(0,0,0,0.85)" style="pointer-events:none;"/>';
|
||||||
terminalHtml += '<text y="24" text-anchor="middle" fill="#fff" font-size="10" font-weight="bold">' + labelText + '</text>';
|
terminalHtml += '<text y="24" text-anchor="middle" fill="#fff" font-size="10" font-weight="bold" style="pointer-events:none;">' + labelText + '</text>';
|
||||||
}
|
}
|
||||||
terminalHtml += '</g>';
|
terminalHtml += '</g>';
|
||||||
});
|
});
|
||||||
|
|
@ -7129,6 +7176,9 @@
|
||||||
var row = term.row !== undefined ? term.row : rowIdx;
|
var row = term.row !== undefined ? term.row : rowIdx;
|
||||||
var ty = y + blockHeight + 7 + (row * terminalSpacing);
|
var ty = y + blockHeight + 7 + (row * terminalSpacing);
|
||||||
|
|
||||||
|
// Get connection color for this terminal (or default gray)
|
||||||
|
var terminalColor = self.getTerminalConnectionColor(eq.id, term.id) || defaultTerminalColor;
|
||||||
|
|
||||||
terminalHtml += '<g class="schematic-terminal" ';
|
terminalHtml += '<g class="schematic-terminal" ';
|
||||||
terminalHtml += 'data-equipment-id="' + eq.id + '" data-terminal-id="' + term.id + '" ';
|
terminalHtml += 'data-equipment-id="' + eq.id + '" data-terminal-id="' + term.id + '" ';
|
||||||
terminalHtml += 'transform="translate(' + tx + ',' + ty + ')">';
|
terminalHtml += 'transform="translate(' + tx + ',' + ty + ')">';
|
||||||
|
|
@ -7141,12 +7191,12 @@
|
||||||
|
|
||||||
if (colTerminals.length > 1) {
|
if (colTerminals.length > 1) {
|
||||||
// Stacked: place label to the right of the terminal
|
// Stacked: place label to the right of the terminal
|
||||||
terminalHtml += '<rect x="8" y="-7" width="' + labelWidth + '" height="14" rx="3" fill="rgba(0,0,0,0.85)"/>';
|
terminalHtml += '<rect x="8" y="-7" width="' + labelWidth + '" height="14" rx="3" fill="rgba(0,0,0,0.85)" style="pointer-events:none;"/>';
|
||||||
terminalHtml += '<text x="' + (8 + labelWidth/2) + '" y="3" text-anchor="middle" fill="#fff" font-size="9" font-weight="bold">' + labelText + '</text>';
|
terminalHtml += '<text x="' + (8 + labelWidth/2) + '" y="3" text-anchor="middle" fill="#fff" font-size="9" font-weight="bold" style="pointer-events:none;">' + labelText + '</text>';
|
||||||
} else {
|
} else {
|
||||||
// Single: place label above in block
|
// Single: place label above in block
|
||||||
terminalHtml += '<rect x="' + (-labelWidth/2) + '" y="-25" width="' + labelWidth + '" height="14" rx="3" fill="rgba(0,0,0,0.85)"/>';
|
terminalHtml += '<rect x="' + (-labelWidth/2) + '" y="-25" width="' + labelWidth + '" height="14" rx="3" fill="rgba(0,0,0,0.85)" style="pointer-events:none;"/>';
|
||||||
terminalHtml += '<text y="-15" text-anchor="middle" fill="#fff" font-size="10" font-weight="bold">' + labelText + '</text>';
|
terminalHtml += '<text y="-15" text-anchor="middle" fill="#fff" font-size="10" font-weight="bold" style="pointer-events:none;">' + labelText + '</text>';
|
||||||
}
|
}
|
||||||
terminalHtml += '</g>';
|
terminalHtml += '</g>';
|
||||||
});
|
});
|
||||||
|
|
@ -9827,10 +9877,10 @@
|
||||||
$btn.addClass('active').css('background', '#27ae60');
|
$btn.addClass('active').css('background', '#27ae60');
|
||||||
this.showMessage('Manueller Zeichenmodus: Klicke Terminal oder Leitung für Startpunkt', 'info');
|
this.showMessage('Manueller Zeichenmodus: Klicke Terminal oder Leitung für Startpunkt', 'info');
|
||||||
this.showWireGrid();
|
this.showWireGrid();
|
||||||
// Highlight all terminals to show they are clickable
|
// Set crosshair on ENTIRE SVG in draw mode
|
||||||
$(this.svgElement).find('.schematic-terminal').css('cursor', 'crosshair');
|
$(this.svgElement).css('cursor', 'crosshair');
|
||||||
// Also highlight connections as clickable for junction
|
// Also on all child elements to prevent override
|
||||||
$(this.svgElement).find('.schematic-connection-hitarea').css('cursor', 'crosshair');
|
$(this.svgElement).find('*').css('cursor', 'inherit');
|
||||||
} else {
|
} else {
|
||||||
$btn.removeClass('active').css('background', '');
|
$btn.removeClass('active').css('background', '');
|
||||||
this.cancelWireDrawing();
|
this.cancelWireDrawing();
|
||||||
|
|
@ -10608,8 +10658,9 @@
|
||||||
var $btn = $('.schematic-wire-draw-toggle');
|
var $btn = $('.schematic-wire-draw-toggle');
|
||||||
$btn.removeClass('active').css('background', '');
|
$btn.removeClass('active').css('background', '');
|
||||||
$(this.svgElement).find('.schematic-terminal-circle').attr('stroke', '#fff').attr('stroke-width', '2');
|
$(this.svgElement).find('.schematic-terminal-circle').attr('stroke', '#fff').attr('stroke-width', '2');
|
||||||
$(this.svgElement).find('.schematic-terminal').css('cursor', '');
|
// Reset SVG and all child cursors
|
||||||
$(this.svgElement).find('.schematic-connection-hitarea').css('cursor', '');
|
$(this.svgElement).css('cursor', '');
|
||||||
|
$(this.svgElement).find('*').css('cursor', '');
|
||||||
} else {
|
} else {
|
||||||
// Keep draw mode active - just reset terminal highlights
|
// Keep draw mode active - just reset terminal highlights
|
||||||
$(this.svgElement).find('.schematic-terminal-circle').attr('stroke', '#fff').attr('stroke-width', '2');
|
$(this.svgElement).find('.schematic-terminal-circle').attr('stroke', '#fff').attr('stroke-width', '2');
|
||||||
|
|
@ -11635,8 +11686,9 @@
|
||||||
// Activate wire draw UI
|
// Activate wire draw UI
|
||||||
var $btn = $('.schematic-wire-draw-toggle');
|
var $btn = $('.schematic-wire-draw-toggle');
|
||||||
$btn.addClass('active').css('background', '#f39c12'); // Orange for extend mode
|
$btn.addClass('active').css('background', '#f39c12'); // Orange for extend mode
|
||||||
$(this.svgElement).find('.schematic-terminal').css('cursor', 'crosshair');
|
// Set crosshair on entire SVG in extend mode
|
||||||
$(this.svgElement).find('.schematic-connection-hitarea').css('cursor', 'crosshair');
|
$(this.svgElement).css('cursor', 'crosshair');
|
||||||
|
$(this.svgElement).find('*').css('cursor', 'inherit');
|
||||||
|
|
||||||
// Show start marker at end point
|
// Show start marker at end point
|
||||||
this.showExtendStartMarker(endPoint);
|
this.showExtendStartMarker(endPoint);
|
||||||
|
|
|
||||||
0
js/kundenkarte_cytoscape.js
Executable file → Normal file
0
js/kundenkarte_cytoscape.js
Executable file → Normal file
0
js/layout-base.js
Executable file → Normal file
0
js/layout-base.js
Executable file → Normal file
0
js/pathfinding.min.js
vendored
Executable file → Normal file
0
js/pathfinding.min.js
vendored
Executable file → Normal file
128
js/pwa.js
Executable file → Normal file
128
js/pwa.js
Executable file → Normal file
|
|
@ -36,6 +36,9 @@
|
||||||
offlineQueue: [],
|
offlineQueue: [],
|
||||||
isOnline: navigator.onLine,
|
isOnline: navigator.onLine,
|
||||||
|
|
||||||
|
// Display settings
|
||||||
|
showConnectionLines: false, // Leitungen standardmäßig ausgeblendet
|
||||||
|
|
||||||
// Current modal state
|
// Current modal state
|
||||||
currentCarrierId: null,
|
currentCarrierId: null,
|
||||||
editCarrierId: null, // null = Add-Modus, ID = Edit-Modus (Hutschiene)
|
editCarrierId: null, // null = Add-Modus, ID = Edit-Modus (Hutschiene)
|
||||||
|
|
@ -186,6 +189,7 @@
|
||||||
// Editor actions
|
// Editor actions
|
||||||
$('#btn-add-panel').on('click', () => openModal('add-panel'));
|
$('#btn-add-panel').on('click', () => openModal('add-panel'));
|
||||||
$('#btn-save-panel').on('click', handleSavePanel);
|
$('#btn-save-panel').on('click', handleSavePanel);
|
||||||
|
$('#btn-toggle-wires').on('click', handleToggleWires);
|
||||||
|
|
||||||
$('#editor-content').on('click', '.btn-add-carrier', handleAddCarrier);
|
$('#editor-content').on('click', '.btn-add-carrier', handleAddCarrier);
|
||||||
$('#editor-content').on('click', '.carrier-header', handleCarrierClick);
|
$('#editor-content').on('click', '.carrier-header', handleCarrierClick);
|
||||||
|
|
@ -1152,14 +1156,25 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render SVG connection lines from path_data
|
* Render SVG connection lines between equipment
|
||||||
* Only shows connections that were manually drawn on the website
|
* PWA uses different layout than desktop, so we calculate positions dynamically
|
||||||
*/
|
*/
|
||||||
function renderConnectionLines() {
|
function renderConnectionLines() {
|
||||||
|
// Remove existing SVG overlays first
|
||||||
|
$('.connection-lines-svg').remove();
|
||||||
|
|
||||||
|
// Only render if setting is enabled
|
||||||
|
if (!App.showConnectionLines) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!App.connections || App.connections.length === 0) {
|
if (!App.connections || App.connections.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Desktop reference dimensions
|
||||||
|
const DESKTOP_TE_WIDTH = 56;
|
||||||
|
|
||||||
// Für jede Hutschiene ein SVG-Overlay erstellen
|
// Für jede Hutschiene ein SVG-Overlay erstellen
|
||||||
$('.carrier-card').each(function() {
|
$('.carrier-card').each(function() {
|
||||||
const $carrier = $(this);
|
const $carrier = $(this);
|
||||||
|
|
@ -1172,6 +1187,18 @@
|
||||||
const carrierEquipment = App.equipment.filter(e => e.fk_carrier == carrierId);
|
const carrierEquipment = App.equipment.filter(e => e.fk_carrier == carrierId);
|
||||||
const equipmentIds = carrierEquipment.map(e => e.id);
|
const equipmentIds = carrierEquipment.map(e => e.id);
|
||||||
|
|
||||||
|
// Carrier-Daten für Total-TE
|
||||||
|
const carrier = App.carriers.find(c => c.id == carrierId);
|
||||||
|
const totalTe = carrier ? (parseInt(carrier.total_te) || 12) : 12;
|
||||||
|
|
||||||
|
// PWA TE-Breite berechnen
|
||||||
|
const carrierWidth = $content.width();
|
||||||
|
const pwaTeWidth = carrierWidth / (totalTe + 1); // +1 für den Add-Button
|
||||||
|
|
||||||
|
// Scale factor: PWA-Breite / Desktop-Breite
|
||||||
|
const scaleX = pwaTeWidth / DESKTOP_TE_WIDTH;
|
||||||
|
const scaleY = scaleX * 0.8; // Y etwas weniger skalieren (PWA ist kompakter)
|
||||||
|
|
||||||
// Verbindungen filtern die zu dieser Hutschiene gehören
|
// Verbindungen filtern die zu dieser Hutschiene gehören
|
||||||
const carrierConnections = App.connections.filter(c =>
|
const carrierConnections = App.connections.filter(c =>
|
||||||
equipmentIds.includes(parseInt(c.fk_source)) ||
|
equipmentIds.includes(parseInt(c.fk_source)) ||
|
||||||
|
|
@ -1195,16 +1222,88 @@
|
||||||
|
|
||||||
const color = conn.color || getPhaseColor(conn.connection_type);
|
const color = conn.color || getPhaseColor(conn.connection_type);
|
||||||
|
|
||||||
|
// Transform path_data coordinates to PWA scale
|
||||||
|
const scaledPath = transformPathData(conn.path_data, scaleX, scaleY);
|
||||||
|
|
||||||
// Schatten-Pfad für bessere Sichtbarkeit
|
// Schatten-Pfad für bessere Sichtbarkeit
|
||||||
svgContent += `<path class="connection-shadow" d="${conn.path_data}" />`;
|
svgContent += `<path class="connection-shadow" d="${scaledPath}" />`;
|
||||||
// Hauptpfad
|
// Hauptpfad
|
||||||
svgContent += `<path class="connection-line" d="${conn.path_data}" style="stroke:${color}" data-connection-id="${conn.id}" />`;
|
svgContent += `<path class="connection-line" d="${scaledPath}" style="stroke:${color}" data-connection-id="${conn.id}" />`;
|
||||||
|
|
||||||
|
// Label falls vorhanden
|
||||||
|
if (conn.output_label) {
|
||||||
|
const labelPos = getPathMidpoint(scaledPath);
|
||||||
|
if (labelPos) {
|
||||||
|
const labelWidth = Math.min(conn.output_label.length * 6 + 10, 80);
|
||||||
|
svgContent += `<rect x="${labelPos.x - labelWidth/2}" y="${labelPos.y - 8}" width="${labelWidth}" height="16" rx="3" fill="#1a1a1a" stroke="${color}" stroke-width="1"/>`;
|
||||||
|
svgContent += `<text x="${labelPos.x}" y="${labelPos.y + 4}" text-anchor="middle" fill="${color}" font-size="10" font-weight="bold">${escapeHtml(conn.output_label)}</text>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$svg.html(svgContent);
|
$svg.html(svgContent);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform path data coordinates by scale factors
|
||||||
|
*/
|
||||||
|
function transformPathData(pathData, scaleX, scaleY) {
|
||||||
|
if (!pathData) return '';
|
||||||
|
|
||||||
|
// Parse and transform coordinates
|
||||||
|
return pathData.replace(/([ML])\s*([\d.-]+)\s+([\d.-]+)/gi, function(match, cmd, x, y) {
|
||||||
|
const newX = (parseFloat(x) * scaleX).toFixed(1);
|
||||||
|
const newY = (parseFloat(y) * scaleY).toFixed(1);
|
||||||
|
return `${cmd} ${newX} ${newY}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get midpoint of a path for label positioning
|
||||||
|
*/
|
||||||
|
function getPathMidpoint(pathData) {
|
||||||
|
if (!pathData) return null;
|
||||||
|
|
||||||
|
const points = [];
|
||||||
|
const regex = /[ML]\s*([\d.-]+)\s+([\d.-]+)/gi;
|
||||||
|
let match;
|
||||||
|
|
||||||
|
while ((match = regex.exec(pathData)) !== null) {
|
||||||
|
points.push({ x: parseFloat(match[1]), y: parseFloat(match[2]) });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (points.length < 2) return null;
|
||||||
|
|
||||||
|
// Calculate midpoint along path
|
||||||
|
let totalLength = 0;
|
||||||
|
const segments = [];
|
||||||
|
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
const dx = points[i].x - points[i-1].x;
|
||||||
|
const dy = points[i].y - points[i-1].y;
|
||||||
|
const len = Math.sqrt(dx*dx + dy*dy);
|
||||||
|
segments.push({ start: points[i-1], end: points[i], length: len });
|
||||||
|
totalLength += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
const halfLength = totalLength / 2;
|
||||||
|
let accumulated = 0;
|
||||||
|
|
||||||
|
for (const seg of segments) {
|
||||||
|
if (accumulated + seg.length >= halfLength) {
|
||||||
|
const t = (halfLength - accumulated) / seg.length;
|
||||||
|
return {
|
||||||
|
x: seg.start.x + t * (seg.end.x - seg.start.x),
|
||||||
|
y: seg.start.y + t * (seg.end.y - seg.start.y)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
accumulated += seg.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { x: (points[0].x + points[points.length-1].x) / 2, y: (points[0].y + points[points.length-1].y) / 2 };
|
||||||
|
}
|
||||||
|
|
||||||
function renderTypeGrid() {
|
function renderTypeGrid() {
|
||||||
const categoryLabels = {
|
const categoryLabels = {
|
||||||
'automat': 'Leitungsschutz',
|
'automat': 'Leitungsschutz',
|
||||||
|
|
@ -1238,6 +1337,27 @@
|
||||||
$('#type-grid').html(html);
|
$('#type-grid').html(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// WIRE DISPLAY TOGGLE
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
function handleToggleWires() {
|
||||||
|
App.showConnectionLines = !App.showConnectionLines;
|
||||||
|
|
||||||
|
// Update button appearance
|
||||||
|
const $btn = $('#btn-toggle-wires');
|
||||||
|
if (App.showConnectionLines) {
|
||||||
|
$btn.addClass('active');
|
||||||
|
$btn.attr('title', 'Leitungen ausblenden');
|
||||||
|
} else {
|
||||||
|
$btn.removeClass('active');
|
||||||
|
$btn.attr('title', 'Leitungen einblenden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-render connection lines
|
||||||
|
renderConnectionLines();
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// PANEL (FELD) ACTIONS
|
// PANEL (FELD) ACTIONS
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|
|
||||||
0
kundenkarteindex.php
Executable file → Normal file
0
kundenkarteindex.php
Executable file → Normal file
0
langs/de_DE/kundenkarte.lang
Executable file → Normal file
0
langs/de_DE/kundenkarte.lang
Executable file → Normal file
0
langs/en_US/kundenkarte.lang
Executable file → Normal file
0
langs/en_US/kundenkarte.lang
Executable file → Normal file
0
lib/graph_view.lib.php
Executable file → Normal file
0
lib/graph_view.lib.php
Executable file → Normal file
0
lib/kundenkarte.lib.php
Executable file → Normal file
0
lib/kundenkarte.lib.php
Executable file → Normal file
0
manifest.json
Executable file → Normal file
0
manifest.json
Executable file → Normal file
0
modulebuilder.txt
Executable file → Normal file
0
modulebuilder.txt
Executable file → Normal file
3
pwa.php
Executable file → Normal file
3
pwa.php
Executable file → Normal file
|
|
@ -133,6 +133,9 @@ $themeColor = getDolGlobalString('THEME_ELDY_TOPMENU_BACK1', '#3498db');
|
||||||
<svg viewBox="0 0 24 24"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/></svg>
|
<svg viewBox="0 0 24 24"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z"/></svg>
|
||||||
<span id="sync-badge" class="sync-badge hidden">0</span>
|
<span id="sync-badge" class="sync-badge hidden">0</span>
|
||||||
</button>
|
</button>
|
||||||
|
<button id="btn-toggle-wires" class="btn-icon" title="Leitungen ein-/ausblenden">
|
||||||
|
<svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" class="wire-icon-off"/><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17l-4-4 1.4-1.4 2.6 2.6 6.6-6.6L17 9l-8 8z" class="wire-icon-on hidden"/></svg>
|
||||||
|
</button>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div id="editor-content" class="editor-content">
|
<div id="editor-content" class="editor-content">
|
||||||
|
|
|
||||||
0
pwa_auth.php
Executable file → Normal file
0
pwa_auth.php
Executable file → Normal file
0
sql/data.sql
Executable file → Normal file
0
sql/data.sql
Executable file → Normal file
0
sql/data_building_types.sql
Executable file → Normal file
0
sql/data_building_types.sql
Executable file → Normal file
0
sql/data_busbar_types.sql
Executable file → Normal file
0
sql/data_busbar_types.sql
Executable file → Normal file
0
sql/data_medium_types.sql
Executable file → Normal file
0
sql/data_medium_types.sql
Executable file → Normal file
0
sql/data_terminal_types.sql
Executable file → Normal file
0
sql/data_terminal_types.sql
Executable file → Normal file
0
sql/dolibarr_allversions.sql
Executable file → Normal file
0
sql/dolibarr_allversions.sql
Executable file → Normal file
0
sql/llx_c_kundenkarte_anlage_system.key.sql
Executable file → Normal file
0
sql/llx_c_kundenkarte_anlage_system.key.sql
Executable file → Normal file
0
sql/llx_c_kundenkarte_anlage_system.sql
Executable file → Normal file
0
sql/llx_c_kundenkarte_anlage_system.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_connection.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_connection.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_connection.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_connection.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_contact.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_contact.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_files.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_files.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_files.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_files.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_type.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_type.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_type.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_type.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_type_field.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_type_field.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_type_field.sql
Executable file → Normal file
0
sql/llx_kundenkarte_anlage_type_field.sql
Executable file → Normal file
0
sql/llx_kundenkarte_audit_log.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_audit_log.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_audit_log.sql
Executable file → Normal file
0
sql/llx_kundenkarte_audit_log.sql
Executable file → Normal file
0
sql/llx_kundenkarte_building_type.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_building_type.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_building_type.sql
Executable file → Normal file
0
sql/llx_kundenkarte_building_type.sql
Executable file → Normal file
0
sql/llx_kundenkarte_busbar_type.key.sql
Executable file → Normal file
0
sql/llx_kundenkarte_busbar_type.key.sql
Executable file → Normal file
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue