Community
    • Categories
    • Recent
    • Popular
    • Users
    • Search
    • Register
    • Login

    Switch Ports Sortierung

    Scheduled Pinned Locked Moved Betrieb
    13 Posts 2 Posters 524 Views 2 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • StefanP74S Offline
      StefanP74
      last edited by StefanP74

      Servus,

      ich habe via JDisc einen neuen Switch inventarisiert und die Daten ins i-doit 32 pro importiert.
      Die Port-Nummerierung ist, wie man unten erkennen kann, völlig durcheinander und ich sehe keine Möglichkeit, dies zu ändern.
      Ja, die führenden Nullen fehlen bei den Ports 1-9 ... dennoch hat es mit dieser "Sortierung" nicht viel zu tun, somit bin ich etwas verwirrt, wieso das so durcheinander angezeigt wird.
      Bei den weiteren Switches bzw. Stacks, ist dies nicht der Fall, diese sind aber schon seit Jahren im System.

      Ich habe da einen Verdacht: Wird anstatt des Portnamens möglichweise die ID des Datensatzes verwendet als primary sort?

      idoit_switch_numbers_2024082201.JPG

      LFischerL 1 Reply Last reply Reply Quote 0
      • LFischerL Offline
        LFischer @StefanP74
        last edited by

        Hallo @StefanP74,

        das Thema "Sortierung" ist leider sehr schwierig, da es gefühlt keinen richtigen Weg gibt, der alle glücklich macht. Aktuell gibt es eine Reihe an Bedingungen für die Verkabelungsansicht:

        • Um intern verkabelte Anschlüsse beieinander zu halten, werden diese so gut es geht zusammen sortiert (Eingang und Ausgang auf gleicher höhe)
        • Intern nicht verkabelte Anschlüsse werden nach unten sortiert, damit die interne Verkabelung etwas ordentlicher wird
        • Anschlussnamen werden aufgesplittet und numerisch sowie alphabetisch sortiert (sodass "Port 9" vor "Port 10" kommt)

        Nachdem diese Regeln durchlaufen sind, bleibt es aber weiterhin so, dass wir von links nach rechts sortieren. In deinem Fall führt das leider zu einem unschönen Ergebnis, da die rechte Seite nicht weiter sortiert wird, um die vorherige Logik nicht zunichte zu machen.

        Ich glaube, die einzige "saubere" Lösung wäre, eine optionale Sortierung pro Seite (Ein- und Ausgänge) anzubieten. Das ist jedoch mit erheblichem Aufwand verbunden 😞 Ich weiß nicht, ob wir das in nächster Zeit angehen werden.

        Ich hoffe ich konnte zumindest etwas Licht ins Dunkle bringen

        Viele Grüße
        Leo

        StefanP74S 1 Reply Last reply Reply Quote 0
        • StefanP74S Offline
          StefanP74 @LFischer
          last edited by

          Hallo @LFischer,

          danke für die Info, ich verstehe es nur nicht ganz ... seitens der Programmierlogik.
          Meine Gedanken zu dem Thema, vielleicht sehe ich das auch zu locker. 😉

          Wenn ich einen Eingang mit einem Ausgang verbunden habe, dann ist nur die Sortierung der Eingänge (also links) nötig, da die beiden mit einander verbunden sind und der Ausgang entsprechend gereiht wird, anhand der Abhängigkeit zum Eingang.

          Hat ein Eingang mehrere Ausgänge, dann werden zusätzlich die Ausgänge mit Abhängigkeit zum jeweiligen Eingang, ebenso sortiert.

          Hat ein Eingang keine Abhängigkeit zu einem Ausgang, dann werden diese zB. unten, aber dennoch sortiert angezeigt, Eingang wie auch Ausgang.

          LG Stefan

          LFischerL 1 Reply Last reply Reply Quote 0
          • LFischerL Offline
            LFischer @StefanP74
            last edited by

            Hallo @StefanP74

            ich glaube genau dieser Fall wird aktuell nicht berücksichtigt 🤔

            Hat ein Eingang mehrere Ausgänge, dann werden zusätzlich die Ausgänge mit Abhängigkeit zum jeweiligen Eingang, ebenso sortiert.

            Ich werde mir das aber noch mal lokal nachbauen und anschauen. Vielleicht lässt es sich ja doch noch irgendwie einbauen ohne etwas anderes kaputt zu machen 😉

            Viele Grüße
            Leo

            StefanP74S 1 Reply Last reply Reply Quote 0
            • StefanP74S Offline
              StefanP74 @LFischer
              last edited by

              Hallo @LFischer,

              ich lege meine Hoffnung in deine Hände 😁
              Danke, wäre toll wenn das klappen würde.

              LG Stefan

              LFischerL 1 Reply Last reply Reply Quote 0
              • LFischerL Offline
                LFischer @StefanP74
                last edited by LFischer

                Hey @StefanP74

                ich glaube ich habe etwas gefunden - könntest du das vielleicht kurz bei dir ausprobieren und schauen ob es ggf. zu unerwünschten Seiteneffekten kommt? Ich habe das mit der Add-on Version 1.4 geprüft.

                Dazu bitte in die folgende Datei navigieren (ausgehend vom i-doit Verzeichnis) src/classes/modules/cabling/assets/js/cabling.js

                Hier auf Zeile 254 steht folgendes:

                // Then sort by "toIndex" to keep internally wired connectors near by each other.
                if (a.data.toIndex && b.data.toIndex) {
                    return a.data.toIndex - b.data.toIndex
                }
                

                Das bitte mal mit folgender kleinen Änderung anpassen:

                // Then sort by "toIndex" to keep internally wired connectors near by each other.
                if (a.data.toIndex && b.data.toIndex && a.data.toIndex !== b.data.toIndex) {
                    return a.data.toIndex - b.data.toIndex
                }
                

                Das Problem ist nämlich das die Ausgänge alle auf den gleichen Eingang zeigen - bedeutet hier das der a.data.toIndex und b.data.toIndex den identischen Wert beinhalten. Das Ergebnis der Sortierung ist in diesem Fall 0 was so viel heißt wie: "Bleib wo du bist".

                In diesem Fall soll aber die Sortierung nach Namen übernehmen. Aus diesem Grund ergänzen wir die Bedingung um a.data.toIndex ist ungleich b.data.toIndex.

                Wenn das soweit passt würde ich das im Code übernehmen sodass diese Anpassung in der nächsten Version landet 🙂

                Viele Grüße
                Leo

                StefanP74S 1 Reply Last reply Reply Quote 0
                • StefanP74S Offline
                  StefanP74 @LFischer
                  last edited by

                  Hallo @LFischer,

                  best support ever! 😄 👍
                  Funktioniert hervorragend, sehr fein, danke.

                  idoit_port_no_20240930_01.JPG

                  Super, danke.
                  Ich konnte bei den anderen Verbindungen (bis auf das noch bestehende Problem "chaotische Verkabelung", bei nachträglich angelegten Ports) nichts negatives feststellen.

                  Problem chaotische Verkabelung:
                  idoit_port_chaos_20240830_01.JPG
                  Das ist wohl ein ganz anderes Thema.

                  Danke jedenfalls für den super tollen raschen Fix.
                  Wenn du heute Abend das Gefühl hast "hääää was war das denn?" ... das war ich, ich habe ein paar Bier auf dich getrunken 😁

                  LG Stefan

                  LFischerL 1 Reply Last reply Reply Quote 0
                  • LFischerL Offline
                    LFischer @StefanP74
                    last edited by LFischer

                    Hey @StefanP74

                    freut mich das ich dir damit weiterhelfen konnte 😄 Bzgl. dem "Chaotische Verkabelung" Problem - ist das erst durch den Fix geschehen? Denn genau den zuständigen Code habe ich angepasst...

                    Wäre natürlich schön wenn der Fix nur Probleme löst anstatt auch neue zu schaffen 😞

                    Ich schaue mal ob ich auch dieses Problem nachvollziehen (und ggf. fixen) kann

                    VG Leo

                    edit

                    3479e8b6-ff8a-4e86-b34a-497faf203a50-image.png

                    Okay, ich kann es nachstellen... Mal sehen ob ich das auch noch hinbekomme 😄

                    edit 2

                    Ich glaube auch hier habe ich das Problem gefunden... Es ist aber etwa schwieriger zu lösen 😕 Es ist nämlich so dass die toIndex Werte vom Backend vorbereitet werden... Die Sortierung passiert dann aber im Frontend und ändert die Indexe, sodass diese dann nicht mehr korrekt sind.
                    Mal sehen wie ich das löse 😄

                    StefanP74S 1 Reply Last reply Reply Quote 0
                    • StefanP74S Offline
                      StefanP74 @LFischer
                      last edited by StefanP74

                      @LFischer

                      nein, das ist nicht neu dazugekommen.

                      Edit: Wäre genial wenn du das lösen könntest. 🖖

                      LG Stefan

                      LFischerL 1 Reply Last reply Reply Quote 0
                      • LFischerL Offline
                        LFischer @StefanP74
                        last edited by LFischer

                        Hey @StefanP74

                        ich war ein wenig fleißig und habe etwas erarbeitet 😉 Dieses mal betrifft es aber ein paar mehr Zeilen - ich glaube es ist einfacher die komplette Datei zu tauschen. Leider ist es im Forum nicht möglich die ganze Datei hochzuladen...

                        /**
                         * i-doit cabling visualization javascript base class.
                         *
                         * @author  Leonard Fischer <lfischer@i-doit.com>
                         */
                        window.Cabling = Class.create({
                            $element:      null,
                            data:          null,
                            cache:         null,
                            svg:           null,
                            vis:           null,
                            zoom:          null,
                            options:       {},
                            indexMapping:  [],
                            rootContainer: {
                                height:   0,
                                matching: []
                            },
                        
                            getOptions: function () {
                                return this.options;
                            },
                        
                            getOption: function (option) {
                                return this.options[option];
                            },
                        
                            setOption: function (option, value) {
                                this.options[option] = value;
                        
                                return this;
                            },
                        
                            getSelectedElements: function () {
                                // This method should be used to get all selected cable paths.
                                // this.svg.selectAll('.selected');
                            },
                        
                            initialize: function ($el, data, options) {
                                var that = this;
                        
                                that.$element = $el;
                                that.data = data || [];
                                that.options = {
                                    authEdit:               false, // Defines if the cabling view will allow any editing.
                                    minZoomLevel:           0.1,   // Defines the minimal zoom level.
                                    maxZoomLevel:           1.5,   // Defines the maximal zoom level.
                                    objectTypeData:         {},    // JSON with all necessary object type data (name, color, ...).
                                    connectorTypeData:      {},    // JSON with all necessary connector type data (name, color, ...).
                                    objectTypeFilter:       [],    // Array pf object types, that shall not be displayed.
                                    onAfterProcess:         null,  // 'Complete' event for when the rendering has finished.
                                    onObjSelect:            null,  // Click event for a object node.
                                    onObjUnselect:          null,  // Event for when a object gets unselected.
                                    onCableSelect:          null,  // Click event for a cable.
                                    onConnectorSelect:      null,  // Click event for a connector.
                                    onConnectorUnselect:    null,  // Event for when a connector gets unselected.
                                    onObjAcceptDrag:        null,  // Event for when a object gets unselected.
                                    onObjAbortDrag:         null,  // Event for when a object gets unselected.
                                    width:                  null,  // This can be used to change the viewpoints width. The SVG element will always remain 100%x100%.
                                    height:                 null,  // This can be used to change the viewpoints height. The SVG element will always remain 100%x100%.
                                    undefinedConnectorType: {
                                        color: '#fff',
                                        title: '-'
                                    },                             // Default 'connector type' object.
                                    undefinedObjectType:    {
                                        color: '#fff',
                                        title: '-'
                                    },                             // Default 'object type' object.
                                    nodeWidth:              150,   // Define the node width.
                                    nodeHeight:             20,    // Define the node heigt.
                                    nodeMarginX:            25,    // Define the horizontal margin between nodes.
                                    nodeMarginY:            25,    // Define the vertical margin between nodes.
                                    displayWiring:          false, // Define if the internal wiring shall be displayed (object boxes will get transparent).
                                    showCableLabels:        false, // Define if cables shall be displayed.
                                    clickableConnectors:    false  // Define if connectors shall be clickable.
                                };
                        
                                that.rootContainer = {
                                    height:   0,
                                    matching: []
                                };
                        
                                // Setting the default width and height.
                                that.options.width = that.$element.getWidth();
                                that.options.height = that.$element.getHeight() + 16;
                        
                                Object.extend(that.options, options || {});
                        
                                that.svg = d3.select($el).append('svg')
                                             .attr('width', that.options.width)
                                             .attr('height', that.options.height);
                        
                                that
                                    .svg.append('rect')
                                    .attr('width', that.options.width)
                                    .attr('height', that.options.height)
                                    .style('fill', 'none')
                                    .style('pointer-events', 'all');
                        
                                // Here we set the <g> after the <rect>, this is necessary for dragging and zooming but still clicking elements inside <g>.
                                that.vis = this.svg.append("g");
                        
                                that.zoom = d3.zoom()
                                    .scaleExtent([
                                        that.options.minZoomLevel,
                                        that.options.maxZoomLevel
                                    ])
                                    .on('zoom', function () {
                                        that.vis.attr('transform', d3.event.transform);
                                    });
                        
                                that.svg
                                    .call(that.zoom)
                                    .call(that.zoom.transform, d3.zoomIdentity.translate(that.options.width / 2, that.options.height / 2));
                        
                                this.appendStyle();
                        
                                return this;
                            },
                        
                            appendStyle: function () {
                                // This method is necessary to include the SVG styles - this will be used in the SVG export.
                                var defs   = this.svg.select('defs'),
                                    isIE11 = !!window.MSInputMethodContext && !!document.documentMode;
                        
                                if (defs.node() === null) {
                                    defs = this.svg.append('defs');
                        
                                    defs.append('style').attr('type', 'text/css').text(
                                        ".cabling-object { \
                                            fill: none;\
                                            stroke: #444;\
                                            stroke-width: 1px;\
                                        }\
                                        text {\
                                            font-family: \"Helvetica Neue\", \"Lucida Grande\", \"Tahoma\", Arial, serif;\
                                            font-size: 11px;\
                                            paint-order: stroke;\
                                            stroke: transparent;\
                                            stroke-width: 0;\
                                            fill: #000;\
                                        }\
                                        text.connector-left-title,\
                                        text.connector-right-title {\
                                            stroke-width: 5px;\
                                            stroke: transparent;\
                                        }\
                                        text.connector-left-title.stroked,\
                                        text.connector-right-title.stroked {\
                                            " + (isIE11 ? "stroke-width: 0;" : "stroke-width: 5px;") + "\
                                            stroke: #fff;\
                                        }\
                                        text.title,\
                                        .linkname text,\
                                        .linkname.clicked rect,\
                                        .clicked rect.title {\
                                            fill: #fff;\
                                        }\
                                        text.title {\
                                            font-weight: bold;\
                                        }\
                                        .linkname rect,\
                                        .linkname.clicked text {\
                                            fill: #000;\
                                        }\
                                        rect.title,\
                                        .clicked text.title {\
                                            fill: #222;\
                                        }\
                                        circle.connector {\
                                            stroke: rgba(0, 0, 0, 0.75);\
                                            stroke-width: 1;\
                                        }\
                                        circle.connector-inner {\
                                            fill: rgba(0, 0, 0, 0.75);\
                                            stroke: none;\
                                        }\
                                        path {\
                                            fill: none;\
                                            stroke: #555;\
                                            stroke-width: 2;\
                                        }"
                                    );
                                }
                            },
                        
                            textFormat: function (text, width) {
                                var result = text;
                        
                                if (width <= 0) {
                                    return '';
                                }
                        
                                d3.select(this).text(result);
                        
                                while (this.getComputedTextLength() > width) {
                                    result = result.substring(0, (result.length - 2));
                                    d3.select(this).text(result);
                                }
                        
                                if (result !== text && width > 2) {
                                    result += '..';
                                }
                        
                                return result;
                            },
                        
                            clearCanvas: function () {
                                this.vis.selectAll('*').remove();
                        
                                this.rootContainer = {
                                    height:   0,
                                    matching: []
                                };
                            },
                        
                            responsive: function () {
                                this.options.width = this.$element.getWidth();
                                this.options.height = this.$element.getHeight() + 16;
                        
                                return this;
                            },
                        
                            preProcess: function () {
                                return this;
                            },
                        
                            process: function () {
                                this.indexMapping = [];
                        
                                return this.preProcess().processSide('left').processSide('right').postProcess();
                            },
                        
                            processSide: function (dir) {
                                var that    = this,
                                    invertX = (dir === 'right'),
                                    cache = this.data[dir];
                        
                                // @see CABLING-49 Implement proper calculation for 'separation'.
                                var tree = d3.tree()
                                    .separation((a, b) => Math.max(1, (a.children || []).length, (b.children || []).length))
                                    .nodeSize([
                                        (that.options.nodeHeight + that.options.nodeMarginY),
                                        (that.options.nodeWidth + that.options.nodeMarginX)
                                    ]);
                        
                                var root = d3.stratify()(cache)
                                    .sort(function (a, b) {
                                        // First sort by 'connected-index' to keep internally wired connectors near by each other.
                                        if (dir === 'right' && a.data.siblingId && b.data.siblingId && a.data.siblingId !== b.data.siblingId) {
                                            // @see CABLING-58 Use the newly created indexMapping to find the proper index.
                                            return this.indexMapping.findIndex((d) => d == a.data.siblingId) - this.indexMapping.findIndex((d) => d == b.data.siblingId);
                                        }
                        
                                        // @see  CABLING-36  Any "unconnected" connector will be moved down, so that no wires cross each other.
                                        if (a.data.siblingId && !b.data.siblingId) {
                                            return -1;
                                        }
                        
                                        if (!a.data.siblingId && b.data.siblingId) {
                                            return 1;
                                        }
                        
                                        // @see CABLING-19 Following code will try to sort the connectors in a more natural way!
                        
                                        // First we split by "non-word" characters (like dots, slashes etc.).
                                        var aParts = a.data.title.split(/\W/),
                                            bParts = b.data.title.split(/\W/),
                                            minParts = Math.min(aParts.length, bParts.length), comparison, i;
                        
                                        for (i = 0; i < minParts; i++) {
                                            if (isNumeric(aParts[i]) && isNumeric(bParts[i])) {
                                                comparison = aParts[i] - bParts[i];
                                            } else {
                                                comparison = aParts[i].localeCompare(bParts[i]);
                                            }
                        
                                            if (comparison !== 0) {
                                                return comparison;
                                            }
                                        }
                        
                                        // If nothing worked out, use the default:
                                        return a.data.title.localeCompare(b.data.title);
                                    }.bind(this));
                        
                                if (dir === 'left') {
                                    this.indexMapping = root.children.map((d) => d.data.id);
                                }
                        
                                var connectorTranslate = function (d) {
                                    if (that.options.clickableConnectors) {
                                        if (d.parent === null || d.parent && d.parent.id === 'root') {
                                            return 'translate(' + (invertX ? 5 : -5) + ',0)';
                                        }
                        
                                        if (d.data.inner) {
                                            return 'translate(' + (invertX ? -5 : that.options.nodeWidth+5) + ',0)';
                                        } else {
                                            return 'translate(' + (invertX ? that.options.nodeWidth+5 : -(that.options.nodeWidth+5)) + ',0)';
                                        }
                                    } else {
                                        if (d.parent === null || d.parent && d.parent.id === 'root') {
                                            return 'translate(0,0)';
                                        }
                        
                                        if (d.data.inner) {
                                            return 'translate(' + (invertX ? 0 : that.options.nodeWidth) + ',0)';
                                        } else {
                                            return 'translate(' + (invertX ? that.options.nodeWidth : -that.options.nodeWidth) + ',0)';
                                        }
                                    }
                                };
                        
                                var linkData = tree(root).links();
                        
                                var cable = that.vis
                                    .selectAll(".cable.cable-" + dir)
                                    .data(linkData);
                        
                                cable
                                    .enter().append("path")
                                    .style("opacity", 0)
                                    .attr("class", "cable cable-" + dir);
                        
                                // After the link data is assigned, we reduce the data to only hold cable information.
                                linkData = linkData.filter(function (d) {
                                    return d.source.id !== 'root' && d.source.data.outer;
                                });
                        
                                // @see  CABLING-35  Show internal cabling
                                that.vis
                                    .selectAll('.internal-link.internal-link-' + dir)
                                    .data((root.children || []).filter((d) => d.data.wiredToItself))
                                    .enter()
                                    .append("path")
                                    .style("opacity", 0)
                                    .attr('class', 'internal-link internal-link-' + dir)
                                    .attr('d', function (d) {
                                        const connection = (root.children || []).find(function (conn) { return conn.id == d.data.connectorId});
                        
                                        if (!connection) {
                                            return '';
                                        }
                        
                                        d.y -= 20;
                                        var xBetween = d.y + 30;
                                        const yBetween = ((d.x + connection.x) / 2);
                        
                                        // Mirror the coordinates for the left side.
                                        if (dir === 'left') {
                                            d.y *= -1;
                                            xBetween *= -1;
                                        }
                        
                        
                                        return 'M' + d.y + ',' + d.x +
                                               ' C' + xBetween + ',' + d.x + ' ' + xBetween + ',' + yBetween + ' ' + xBetween + ',' + yBetween;
                                    })
                                    .interrupt()
                                    .transition().duration(500)
                                    .transition().duration(250)
                                    .style("opacity", 1);
                        
                                var cableLabel = that.vis
                                    .selectAll(".linkname.linkname-" + dir)
                                    .data(linkData)
                                    .enter()
                                    .append("g")
                                    .style("opacity", 0)
                                    .attr("class", "linkname linkname-" + dir)
                                    .attr('data-id', function (d) {
                                        return d.source.data.cableId;
                                    });
                        
                                that.vis
                                    .selectAll(".cable.cable-" + dir)
                                    .classed('cable-root', function (d) {
                                        return (d.source.id === 'root');
                                    })
                                    .interrupt().transition().duration(500)
                                    .attr("d", function (d) {
                                        var fromX  = (d.source.y + (that.options.showCableLabels ? 50 : 125)),
                                            fromX2 = (fromX+20),
                                            fromX3 = (fromX+40),
                                            fromY  = d.source.x,
                                            toX    = (d.target.y + (that.options.showCableLabels ? 50 : 125)),
                                            toY    = d.target.x;
                        
                                        if (d.target.data.doubling) {
                                            toX += 20;
                                        }
                        
                                        if (!invertX) {
                                            fromX *= -1;
                                            fromX2 *= -1;
                                            fromX3 *= -1;
                                            toX *= -1;
                                        }
                        
                                        return "M" + fromX + "," + fromY +
                                               "C" + fromX2 + "," + fromY + " " + fromX2 + "," + toY + " " + fromX3 + "," + toY +
                                               "L" + toX + "," + toY;
                                    })
                                    .transition().duration(250)
                                    .style("opacity", 1)
                                    .style('stroke-dasharray', function (d) {
                                        if (d.target.data.doubling) {
                                            return '2,2';
                                        }
                        
                                        return null;
                                    });
                        
                                cable
                                    .exit()
                                    .interrupt().transition().duration(500)
                                    .style("opacity", 0)
                                    .remove();
                        
                                cableLabel
                                    .append('rect')
                                    .attr('class', 'mouse-pointer')
                                    .attr('height', 14)
                                    .attr('width', 125)
                                    .attr('data-id', function (d) {
                                        return d.source.cableId
                                    })
                                    .on('click', that.selectCableObject.bind(this));
                        
                                cableLabel
                                    .append('text')
                                    .attr('class', 'mouse-pointer')
                                    .attr('dy', 10)
                                    .attr('x', 62.5)
                                    .style('text-anchor', 'middle')
                                    .text(function (d) {
                                        return d.source.data.cableTitle;
                                    })
                                    .on('click', that.selectCableObject.bind(this));
                        
                                that.vis
                                    .selectAll(".linkname.linkname-" + dir)
                                    .classed('hide', !that.options.showCableLabels)
                                    .interrupt().transition().duration(550)
                                    .style('opacity', (that.options.showCableLabels ? 1 : 0))
                                    .attr('transform', function (d) {
                                        var translateX = d.source.y,
                                            translateY = d.source.x;
                        
                                        if (invertX) {
                                            translateX = translateX + 85;
                                        } else {
                                            translateX = translateX + that.options.nodeWidth + 65;
                                        }
                        
                                        if (d.source.parent.id === 'root') {
                                            translateX = translateX - 65;
                                        }
                        
                                        return 'translate(' + (invertX ? '' : '-') + translateX + ',' + translateY + ')';
                                    });
                        
                                var node = that.vis
                                    .selectAll(".node.node-" + dir)
                                    .data(root.descendants());
                        
                                var nodeEnter = node
                                    .enter().append("g")
                                    .style("opacity", 0)
                                    .attr("class", "node node-" + dir)
                                    .classed('root', function (d) {
                                        return d.parent === null;
                                    })
                                    .attr('data-id', function (d) {
                                        return d.id;
                                    });
                        
                                // This will append newly created and already existing nodes.
                                this.vis
                                    .selectAll('.node.node-' + dir)
                                    .transition().duration(500)
                                    .style("opacity", 1)
                                    .attr("transform", function (d) {
                                        var translateX = d.y,
                                            translateY = d.x;
                        
                                        if (d.parent === null) {
                                            return "translate(" + (invertX ? 0 : -that.options.nodeWidth) + "," + translateY + ")";
                                        }
                        
                                        if (d.parent && d.parent.id === 'root') {
                                            return "translate(" + (invertX ? that.options.nodeWidth : -that.options.nodeWidth) + "," + translateY + ")";
                                        }
                        
                                        if (d.data.inner) {
                                            if (!invertX) {
                                                translateX = -(translateX + that.options.nodeWidth);
                                            }
                                        } else {
                                            if (!invertX) {
                                                translateX = -(translateX + that.options.nodeWidth) + (that.options.nodeWidth + that.options.nodeMarginX);
                                            } else {
                                                translateX -= that.options.nodeMarginX;
                                            }
                                        }
                        
                                        return "translate(" + translateX + "," + translateY + ")";
                                    });
                        
                                node.exit()
                                    .interrupt().transition().duration(500)
                                    .style("opacity", 0)
                                    .remove();
                        
                                var container = nodeEnter
                                    .filter(function (d) {
                                        // Only draw boxes for the "root" element and "left" connectors.
                                        return d.parent === null || d.data.inner;
                                    })
                                    .each(function (d) {
                                        // Prepare some data for each node.
                                        d.childNum = (d.children ? d.children.length : 1);
                        
                                        d.minX = d.y;
                                        d.maxX = d.y + (that.options.nodeWidth * 2);
                        
                                        if (d.children) {
                                            d.minY = d.children.first().x;
                                            d.maxY = d.children.last().x + that.options.nodeHeight;
                                        } else {
                                            d.minY = d.x;
                                            d.maxY = d.x + that.options.nodeHeight;
                                        }
                        
                                        d.width = d.maxX - d.minX;
                                        d.height = d.maxY - d.minY;
                                        d.translateX = 0;
                                        d.translateY = -(d.height / 2);
                        
                                        if (d.parent === null) {
                                            if (that.rootContainer.height < d.height) {
                                                that.rootContainer.height = d.height;
                                                that.rootContainer.translateX = d.translateX;
                                                that.rootContainer.translateY = d.translateY;
                                            }
                        
                                            d.width = that.options.nodeWidth;
                                        }
                                    });
                        
                                container
                                    .append('rect')
                                    .attr('class', 'title mouse-pointer')
                                    .attr('width', function (d) {
                                        return d.width;
                                    })
                                    .attr('height', function (d) {
                                        return 20;
                                    })
                                    .attr('data-object-id', function (d) {
                                        return d.data.objectId;
                                    })
                                    .attr('transform', function (d) {
                                        var translateX = d.translateX,
                                            translateY = d.translateY;
                        
                                        if (d.parent && d.parent !== 'root') {
                                            if (!invertX) {
                                                translateX = -that.options.nodeWidth;
                                            }
                                        }
                        
                                        return 'translate(' + translateX + ',' + (translateY - 20) + ')';
                                    })
                                    .on('click', that.selectObject.bind(this));
                        
                                container
                                    .append('rect')
                                    .attr('class', 'body')
                                    .attr('width', function (d) {
                                        return d.width;
                                    })
                                    .attr('height', function (d) {
                                        return d.height;
                                    })
                                    .attr('data-conn', function (d) {
                                        return d.data.title;
                                    })
                                    .attr('transform', function (d) {
                                        var translateX = d.translateX,
                                            translateY = d.translateY;
                        
                                        if (d.parent && d.parent !== 'root') {
                                            if (!invertX) {
                                                translateX = -that.options.nodeWidth;
                                            }
                                        }
                        
                                        return 'translate(' + translateX + ',' + translateY + ')';
                                    })
                                    .attr('fill', function (d) {
                                        if (!that.options.objectTypeData.hasOwnProperty(d.data.objectTypeId)) {
                                            return that.options.undefinedObjectType.color;
                                        }
                        
                                        return that.options.objectTypeData[d.data.objectTypeId].color || that.options.undefinedObjectType.color
                                    });
                        
                                nodeEnter
                                    .filter(function (d) {
                                        return d.parent !== null;
                                    })
                                    .append('circle')
                                    .attr('data-connector-id', function (d) {
                                        return d.data.id;
                                    })
                                    .attr('class', 'connector connector-' + dir)
                                    .attr('transform', connectorTranslate)
                                    .on('click', that.selectConnector.bind(this));
                        
                                nodeEnter
                                    .filter(function (d) {
                                        return d.parent !== null;
                                    })
                                    .append('circle')
                                    .attr('data-connector-id', function (d) {
                                        return d.data.id;
                                    })
                                    .style('opacity', 0)
                                    .attr('class', 'connector-inner hide connector-inner-' + dir)
                                    .attr('r', 4)
                                    .attr('transform', connectorTranslate)
                                    .on('click', that.selectConnector.bind(this));
                        
                                that.vis
                                    .selectAll('circle.connector.connector-' + dir)
                                    .classed('mouse-pointer', that.options.clickableConnectors)
                                    .interrupt().transition().duration(500)
                                    .attr('r', (that.options.clickableConnectors ? 10: 5))
                                    .attr('fill', function (d) {
                                        var connectorType = that.options.connectorTypeData[d.data.connectorType];
                        
                                        return connectorType ? connectorType.color : that.options.undefinedConnectorType.color;
                                    })
                                    .attr('transform', connectorTranslate)
                                    .style('stroke-width', (that.options.clickableConnectors ? 3 : 1));
                        
                                that.vis
                                    .selectAll('circle.connector-inner.connector-inner-' + dir)
                                    .classed('mouse-pointer', that.options.clickableConnectors)
                                    .interrupt().transition().duration(500)
                                    .attr('transform', connectorTranslate)
                                    .style('opacity', (that.options.clickableConnectors ? 1 : 0));
                        
                                container
                                    .filter(function (d) {
                                        return (d.parent !== null || invertX);
                                    })
                                    .append('text')
                                    .attr('class', 'title mouse-pointer')
                                    .attr("dy", function (d) {
                                        if (d.id === 'root') {
                                            return -((that.rootContainer.height / 2) + 7);
                                        }
                        
                                        return -((d.height / 2) + 7);
                                    })
                                    .attr("x", function (d) {
                                        if (d.parent === null) {
                                            return 0
                                        }
                        
                                        return invertX ? that.options.nodeWidth : 0;
                                    })
                                    .style("text-anchor", 'middle')
                                    .text(function (d) {
                                        return d.data.objectTitle;
                                    })
                                    .on('click', that.selectObject.bind(this));
                        
                                nodeEnter
                                    .append("text")
                                    .attr('class', 'connector-' + dir + '-title')
                                    .attr("dy", 3)
                                    .attr("x", function (d) {
                                        if (d.parent !== null && d.parent.id === 'root') {
                                            return invertX ? -25 : 25;
                                        }
                        
                                        if (d.data.outer) {
                                            return invertX ? that.options.nodeWidth-10 : -(that.options.nodeWidth-10);
                                        }
                        
                                        return invertX ? 10 : (that.options.nodeWidth-10);
                                    })
                                    .style("text-anchor", function (d) {
                                        if (d.parent !== null && d.parent.id === 'root' || d.data.outer) {
                                            return invertX ? 'end' : 'start';
                                        }
                        
                                        return invertX ? "start" : "end";
                                    })
                                    .text(function (d) {
                                        return that.textFormat.call(this, d.data.title, (that.options.nodeWidth - 15));
                                    });
                        
                                // @see CABLING-56 Show the full title when hovering connector.
                                nodeEnter.append('title').text(d => d.data.title);
                        
                                // After all calculations have been done, we set the root height.
                                this.vis.selectAll('g.root rect.title')
                                    .attr('transform', function (d) {
                                        return 'translate(' + that.rootContainer.translateX + ',' + (that.rootContainer.translateY - 20) + ')';
                                    });
                        
                                this.vis.selectAll('g.root rect.body')
                                    .attr('height', function () {
                                        return that.rootContainer.height;
                                    })
                                    .attr('transform', function (d) {
                                        return 'translate(' + that.rootContainer.translateX + ',' + that.rootContainer.translateY + ')';
                                    });
                        
                                this.vis.selectAll('rect.body')
                                    .transition().duration(250)
                                    .style('opacity', (this.options.displayWiring ? 0.5 : 1));
                        
                                this.vis
                                    .selectAll(".cable.cable-root.cable-" + dir)
                                    .each(function (d) {
                                        d.fromX = (invertX ? '' : '-') + 100;
                                        d.fromY = d.target.x;
                                        d.toX = (invertX ? '' : '-') + (d.target.y + (that.options.showCableLabels ? 50 : 125));
                                        d.toY = d.target.x;
                        
                                        // If a connector is internally wired, we draw the line to the middle (to visually "connect" them).
                                        if (d.target.data.wired) {
                                            d.fromX = 0; // -25;
                                        }
                        
                                        // If a root connector is not connected, only show a small "stump".
                                        if (!d.target.children) {
                                            d.toX = parseInt((invertX ? '' : '-') + 200);
                                        }
                                    })
                                    .attr('data-index', (d, i) => i)
                                    .interrupt().transition().delay(500).duration(250)
                                    .style('opacity', 1)
                                    .attr('d', function (d) {
                                        // @see  CABLING-35  Cut the 'self wired' connectors more short
                                        if (d.target.data.wiredToItself || false) {
                                            if (dir === 'right') {
                                                d.toX -= 45;
                                            } else {
                                                d.toX += 45;
                                            }
                                        }
                        
                                        if (invertX && d.target.data.wired) {
                                            const index = this.indexMapping.findIndex((i) => i == d.target.data.siblingId);
                                            const $selection = this.vis.select('[data-index="' + index + '"]');
                        
                                            if (index >= 0 && $selection.size()) {
                                                d.fromY = $selection.data()[0].fromY;
                        
                                                return "M" + d.fromX + "," + d.fromY +
                                                       "C" + (d.fromX+20) + "," + d.fromY + " " + (d.fromX+20) + "," + d.toY + " " + (d.fromX+40) + "," + d.toY +
                                                       "L" + d.toX + "," + d.toY;
                                            }
                                        }
                        
                                        return "M" + d.fromX + "," + d.fromY +
                                               "L" + d.toX + "," + d.toY;
                                    }.bind(this));
                        
                                this.vis.selectAll('.connector-' + dir + '-title')
                                    .classed('stroked', this.options.displayWiring);
                        
                                return this;
                            },
                        
                            postProcess: function () {
                                if (Object.isFunction(this.options.onAfterProcess)) {
                                    this.options.onAfterProcess.call(this);
                                }
                        
                                return this;
                            },
                        
                            setData: function (data) {
                                this.data = data;
                        
                                return this;
                            },
                        
                            selectObject: function (d) {
                                var $object = this.vis.selectAll('[data-id="' + d.id + '"]');
                        
                                if (!$object.classed('clicked')) {
                                    this.vis.selectAll('.clicked').classed('clicked', false);
                        
                                    $object.classed('clicked', true);
                        
                                    if (Object.isFunction(this.options.onObjSelect)) {
                                        this.options.onObjSelect.call(this, d);
                                    }
                                }
                        
                                return this;
                            },
                        
                            selectCableObject: function (d) {
                                var $object = this.vis.selectAll('[data-id="' + d.source.data.cableId + '"]');
                        
                                if (!$object.classed('clicked')) {
                                    this.vis.selectAll('.clicked').classed('clicked', false);
                        
                                    $object.classed('clicked', true);
                        
                                    if (Object.isFunction(this.options.onCableSelect)) {
                                        this.options.onCableSelect.call(this, d);
                                    }
                                }
                        
                                return this;
                            },
                        
                            selectConnector: function (d) {
                                var $connector = this.vis.select('circle.connector-inner[data-connector-id="' + d.data.id + '"]');
                        
                                if (! this.options.clickableConnectors) {
                                    return;
                                }
                        
                                $connector.classed('hide', !$connector.classed('hide'));
                        
                                if (Object.isFunction(this.options.onConnectorSelect)) {
                                    this.options.onConnectorSelect.call(this, d);
                                }
                        
                                return this;
                            },
                        
                            unselectConnectors: function (d) {
                                var data = this.vis.selectAll('.connector-inner:not(.hide)').classed('hide', true).data();
                        
                                if (Object.isFunction(this.options.onConnectorUnselect)) {
                                    this.options.onConnectorUnselect.call(this, data);
                                }
                        
                                return this;
                            },
                        
                            unselectObject: function (data) {
                                if (Object.isFunction(this.options.onObjUnselect)) {
                                    this.options.onObjUnselect.call(this, data);
                                }
                        
                                return this;
                            },
                        
                            center: function () {
                                var translateX = (this.options.width / 2),
                                    translateY = (this.options.height / 2);
                        
                                this.vis.attr('transform', "translate(" + translateX + "," + translateY + ")");
                        
                                this.svg.select('rect').call(this.zoom.transform, d3.zoomIdentity.translate(translateX, translateY));
                        
                                return this;
                            }
                        });
                        

                        Die Datei müsste mit diesem neuen Inhalt überschrieben werden 😄

                        Das dürfte weiterhelfen!

                        4b3a1091-f515-4bae-bfc1-f35baeca93b8-image.png

                        VG Leo

                        StefanP74S 1 Reply Last reply Reply Quote 1
                        • StefanP74S Offline
                          StefanP74 @LFischer
                          last edited by

                          Servus @LFischer,

                          fantastico! 👌

                          Vielen Dank, das ist perfekt.
                          Was für ein mächtiger Einsatz. 👍

                          LG Stefan

                          1 Reply Last reply Reply Quote 0
                          • LFischerL Offline
                            LFischer
                            last edited by

                            Kurzes Update: Gelöst in Add-on Version 1.5

                            Die hier beschriebenen Probleme wurden in der Zwischenzeit in Version 1.5 des Add-ons gelöst. Dieses wurde am 26.Februar veröffentlicht 🙂

                            Viele Grüße
                            Leo

                            1 Reply Last reply Reply Quote 0
                            • StefanP74S Offline
                              StefanP74
                              last edited by

                              ... und das erfreute mich ganz besonders 😊 👏

                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post