Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung
在使用jsPlumb过程中,所遇到的问题,以及解决方案,文中引用了《数据结构与算法JavaScript描述》的相关图片和一部分代 码.截图是有点多,有时比较懒,没有太多的时间去详细的编辑.Nach dem Login kopieren
Vorwort
Zuerst ist das UML-Klassendiagramm
Dann ist das Flussdiagramm
Mit den zugehörigen Funktionen von jsPlumb können Sie den Prototyp der ersten Version sehen. Es dauerte fast zwei Monate, unterbrochen von anderen Arbeiten, aber die Grundfunktionen waren noch abgeschlossen.
Tatsächlich Nach Abschluss der Arbeit stellte ich fest, dass nur ein kleiner Teil der Funktionen von jsPlumb verwendet wurde und dass das Verständnis und die Implementierung der internen Datenstruktur nur synchron waren
Hier werden wir die im Projekt aufgetretenen Probleme und die Lösungen zusammenfassen und aufzeichnen. Wenn es eine bessere Methode gibt, weisen Sie sie bitte darauf hin von mehreren Labels auf der Verbindung
Wie im Bild oben gezeigt, habe ich zunächst darüber nachgedacht, beim Verbinden zwei Overlays zu konfigurieren
Natürlich gibt es hier Fallstricke wird wiederholt, dann wird es verwendet. Das letzte wird nicht überlappen, einschließlich der in jsPlumb zwischengespeicherten Daten, nur das letzte bleibt übrigvar j = jsPlumb.getInstance(); j.connect({ source:source, target:target, overlays:[ "Arrow", ["label",{label:"foo1",location:0.2Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung,id:"m1"}], ["label",{label:"foo2",location:0.Zusammenfassung der jsPlumb-Flussdiagramm-ErfahrungZusammenfassung der jsPlumb-Flussdiagramm-Erfahrung,id:"m2"}] ] })
Später entdeckte ich, dass die Konfigurationselemente auch dynamisch geändert werden können
Funktion.importDefaults
j.importDefaults({ ConnectionOverlays: [ ["Arrow", { location: 1, id: "arrow", length: 10, foldback: 0, width: 10 }], ["Label", { label: "n", id: "label-n", location: 0.2Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung, cssClass: "jspl-label" }], ["Label", { label: "1", id: "label-1", location: 0.Zusammenfassung der jsPlumb-Flussdiagramm-ErfahrungZusammenfassung der jsPlumb-Flussdiagramm-Erfahrung, cssClass: "jspl-label" }] ] })
Verwendung von Gruppen
nicht verwendet werden verwendet werden.
Laut Dokumentation bewegen sich, wenn ein Element als Gruppe markiert ist, die Elemente in der Gruppe mit der Bewegung der Gruppe, ebenso wie die Verbindungen, aber das Problem besteht darin, dass, sobald ein Element zu einer Gruppe wird , es kann keine anderen Gruppenelemente akzeptieren, mit anderen Worten, die von ihm bereitgestellte Gruppenmethode kann die Anforderungen natürlich nicht erfüllen. Veröffentlichen Sie zunächst die zusammengefasste Verwendung von Gruppen: Groups
Später wird eine neue Methode übernommen. Methode: Wenn sich der Knoten bewegt, wird die Verbindung dynamisch aktualisiert
j.addGroup({ el:el, id:"one" constrain:true, // 子元素仅限在元素内拖动 droppable:true, // 子元素是否可以放置其他元素 draggable:true, // 默认为true,组是否可以拖动 dropOverride:true ,// 组中的元素是否可以拓展到其他组,为true时表示否,这里的拓展会对dom结构进行修改,而非单纯的位置移动 ghost:true, // 是否创建一个子元素的副本元素 revert:true, // 元素是否可以拖到只有边框可以重合 })
Um die Seite nicht zu blockieren, müssen Sie die Funktionsdrosselung verwenden
j.repaintEverything();
throttle()
Dies ist eine einfache Implementierung. Die Methode besteht hauptsächlich darin, die Anzahl der wiederholt aufgerufenen Ereignisse beim Verschieben von Ereignissen im Dom zu reduzieren und gleichzeitig den Zweck der Ereignisausführung zu erreichen (nur die einmalige Ausführung einer Funktion innerhalb von x zu ermöglichen). Millisekunden);
function throttle(fn,interval){ var canRun = true; return function(){ if(!canRun) return; canRun = false; setTimeout(function(){ fn.apply(this,arguments); canRun = true; },interval ? interval : Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung00); }; };
Mehrschichtige oder einschichtige Datenstrukturanalyse_.throttle()
Es gibt zwei Möglichkeiten, Datenkörper zu verwalten wie diese, die tatsächlich verschachtelte Beziehungen haben,
- , wenn sie für die Verwaltung verwendet werden, besteht der Vorteil darin, dass sie intuitiv ist. Sie können die ungefähre Gesamtstruktur anhand der Ebene kennen, und es ist auch sehr bequem, sie in XML oder HTML zu konvertieren.
- Zeigen Sie alle Knoten in einer Ebene an: ähnlich wie
[ { id:"1", child:{ id:"2", child:{ id:"Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung", child:{} } } } ]
Nach dem Login kopieren
Die Vorteile dieser Struktur sind alle. Auf einer Ebene ist es sehr praktisch, Daten zu suchen und zu ändern, wenn Sie sie analysieren möchten In eine mehrstufige Struktur müssen Sie nur die Rekursion verwenden, um eine neue Struktur zu generieren: Initialisieren Sie das Array einer Ebene. Funktion
kann in eine mehrstufige< umgewandelt werden 🎜>[ { id:"1", child:[{ id:"2" }] }, { id:"2", parentId:"1", child:[{ id:"Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung" }] }, { id:"Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung", parentId:"2", child:[] } ]
Nach dem Login kopierenfunction mt(){ var OBJ; this.root = null; this.Node = function(e) { this.id = e.id; this.name = e.name; this.parentId = e.parentId; this.children = []; }; this.insert=function(e,key){ function add(obj,e){ if(obj.id == e.parentId){ obj.children.push(e); } else { for (var i = 0; i < obj.children.length; i++) { add(obj.children[i], e); } } } if (e != undefined) { e = new this.Node(e); } else { return; } if (this.root == null) { this.root = e; } else { OBJ = this.root; add(OBJ, e); } } this.init = function(data){ var _this = this; for(var i = 0;i<data.length;i++){ _this.insert(data[i]); } return OBJ; } }
Nach dem Login kopierenWenn Sie es in eine HTML-Struktur konvertieren möchten, müssen Sie die Funktion nur geringfügig ändern und schon können Sie es erreichen.
Dies wird vollständig durch Algorithmen erreicht. Zunächst ist das Verständnis des Diagramms der Schlüsselinit
Überprüfen Sie, ob es eine gibt Sackgasse im Prozess (ob es einen Punkt auf dem Pfad gibt, der das Ende des Diagramms nicht erreichen kann)
Sie können sehen, dass die grundlegende Diagrammdarstellung durch eine Adjazenzliste dargestellt werden kann
Und die Konstruktion allein ist es nicht genug, also werfen wir einen Blick auf die grundlegenden Suchmethoden:
function Graph1(v) { this.vertices = v; // 总顶点 this.edges = 0; // 图的边数 this.adj = []; // 通过 for 循环为数组中的每个元素添加一个子数组来存储所有的相邻顶点,[并将所有元素初始化为空字符串。]? for (var i = 0; i < this.vertices; ++i) { this.adj[i] = []; } /** * 当调用这个函数并传入顶点 v 和 w 时,函数会先查找顶点 v 的邻接表,将顶点 w 添加到列表中 * 然后再查找顶点 w 的邻接表,将顶点 v 加入列表。最后,这个函数会将边数加 1。 * @param {[type]} v [第一个顶点] * @param {[type]} w [第二个顶点] */ this.addEdge = function(v, w) { this.adj[v].push(w); this.adj[w].push(v); this.edges++; } /** * 打印所有顶点的关系简单表现形式 * @return {[type]} [description] */ this.showGraph = function() { for (var i = 0; i < this.vertices; ++i) { var str = i + " ->"; for (var j = 0; j < this.vertices; ++j) { if (this.adj[i][j] != undefined) { str += this.adj[i][j] + &#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9; &#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9; } } console.log("表现形式为:" + str); } console.log(this.adj); } }
Breitensuche
/** * 广度优先搜索算法 * @param {[type]} s [description] */ this.bfs = function(s) { var queue = []; this.marked[s] = true; queue.push(s); // 添加到队尾 while (queue.length > 0) { var v = queue.shift(); // 从队首移除 console.log("Visisted vertex: " + v); for (var w of this.adj[v]) { if (!this.marked[w]) { this.edgeTo[w] = v; this.marked[w] = true; queue.push(w); } } } }
而如果看了《数据结构与算法JavaScript描述》这本书,有兴趣的可以去实现下查找最短路径
和拓扑排序
;
这算是找到的比较能理解的方式来计算
以上图为例,这是一个简单的流程图,可以很简单的看出,右边的流程实际上是未完成的,因为无法到达终点,所以是一个非法点,而通过上面的深度搜索,可以看出,只要对深度优先搜索算法进行一定的修改,那么就可以找到从开始到结束的所有的路径,再通过对比,就可以知道哪些点无法到达终点,从而确定非法点.
上代码:
/** * 深度搜索,dfs,解两点之间所有路径 * @param {[type]} v [description] * @return {[type]} [description] */ function Graph2(v) { var _this = this; this.vertices = v; // 总顶点 this.edges = 0; //图的起始边数 this.adj = []; //内部邻接表表现形式 this.marked = []; // 内部顶点访问状态,与邻接表对应 this.path = []; // 路径表示 this.lines = []; // 所有路径汇总 for (var i = 0; i < this.vertices; ++i) { _this.adj[i] = []; } /** * 初始化访问状态 * @return {[type]} [description] */ this.initMarked = function() { for (var i = 0; i < _this.vertices; ++i) { _this.marked[i] = false; } }; /** * 在邻接表中增加节点 * @param {[type]} v [description] * @param {[type]} w [description] */ this.addEdge = function(v, w) { this.adj[v].push(w); this.edges++; }; /** * 返回生成的邻接表 * @return {[type]} [description] */ this.showGraph = function() { return this.adj; }; /** * 深度搜索算法 * @param {[type]} v [起点] * @param {[type]} d [终点] * @param {[type]} path [路径] * @return {[type]} [description] */ this.dfs = function(v, d, path) { var _this = this; this.marked[v] = true; path.push(v); if (v == d) { var arr = []; for (var i = 0; i < path.length; i++) { arr.push(path[i]); } _this.lines.push(arr); } else { for (var w of this.adj[v]) { if (!this.marked[w]) { this.dfs(w, d, path); } } } path.pop(); this.marked[v] = false; }; this.verify = function(arr, start, end) { this.initMarked(); for (var i = 0; i < arr.length; i++) { _this.addEdge(arr[i].from, arr[i].to); } this.dfs(start, end, this.path); return this.lines; }; }
可以看出修改了addEdge()
函数,将邻接表中的双向记录改为单向记录,可以有效避免下图的错误计算:
只计算起点到终点的所有连线有时并不客观,如果出现
这种情况的话,实际上深度遍历并不能计算出最右边的节点是合法的,那么就需要重新修改起点和终点,来推导是否能够到达终点.从而判定该点是否合法.至于其他的,只是多了个返回值,存储了一下计算出来的所有路径.
而在dfs函数中,当满足能够从起点走到终点的,则记录下当前的path中的值,保存到lines中去,而每一次对于path的推入或者推出,保证了只有满足条件的点,才能被返回;
而this.marked[v] = false
,则确保了,在每一次重新计算路径时,都会验证每个点是否存在不同的相对于终点能够到达的路径是否存在.
当然,一定会有更加简单的方法,我这里只是稍微修改了下基础的代码!
redo和undo
这是我觉得最简单却耗时最久的功能,思路都知道:创建一个队列,记录每一次创建一个流程节点,删除一个流程节点,建立一个新的关联关系,删除一个新的关联关系等,都需要记录下来,再通过统一的接口来访问队列,执行操作.
但在具体实现上,jsPlumb的remove确实需要注意一下:
首先,如果需要删除连线,那么使用jsPlumb提供的detach()
方法,就可以删除连线,注意,传入的数据应该是connection
对象.
当然,也可以使用remove()
方法,参数为选择器或者element对象都可以,这个方法删除的是一个节点,包括节点上所有的线.
而jsPlumb中会内部缓存所有的数据,用于刷新,和重连.
那么当我移除一个多层级且内部有连线的情况时,如果只删除最外层的元素,那么内部的连线实际上并没有清除,所以当redo或者移动时,会出现连线的端点有一端会跑到坐标原点,也就是p上(0,0)的地方去.所以清除时,需要注意,要把内部的所有节点依次清除,才不会发生一些莫名其妙的bug.
而在删除和连接连线上,我使用了jsPlumb提供的事件bind(&#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9;connection&#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9;)
和bind("connectionDetached")
,用于判断一条连线被连接或者删除.而在记录这里的redo和undo事件时,尤其要注意,需要首先确定删除和连接时的连线的类型,否则会产生额外的队列事件.
因此,在使用连接事件时,就可以使用
jsPlumb.connect({ source:"foo", target:"bar", parameters:{ "p1":Zusammenfassung der jsPlumb-Flussdiagramm-ErfahrungZusammenfassung der jsPlumb-Flussdiagramm-Erfahrung, "p2":new Date(), "pZusammenfassung der jsPlumb-Flussdiagramm-Erfahrung":function() { console.log("i am pZusammenfassung der jsPlumb-Flussdiagramm-Erfahrung"); } } });
来进行类型的传参,这样事件触发时就可以分类处理.
也可以使用connection.setData()
事件,参数可以指定任意的值,通过connection.getData()
方法,就可以拿到相应的数据了.
而redo和undo本身确实没有什么东西
var defaults = { &#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9;name&#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9;: "mutation", &#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9;afterAddServe&#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9;:$.noop, &#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9;afterUndo&#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9;:$.noop, &#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9;afterRedo&#Zusammenfassung der jsPlumb-Flussdiagramm-Erfahrung9;:$.noop } var mutation = function(options){ this.options = $.extend(true,{},defaults,options); this.list = []; this.index = 0; }; mutation.prototype = { addServe:function(undo,redo){ if(!_.isFunction(undo) || !_.isFunction(redo)) return false; // 说明是在有后续操作时,更新了队列 if(this.canRedo){ this.splice(this.index+1); }; this.list.push({ undo:undo, redo:redo }); console.log(this.list); this.index = this.list.length - 1; _.isFunction(this.options.afterAddServe) && this.options.afterAddServe(this.canUndo(),this.canRedo()); }, /** * 相当于保存之后清空之前的所有保存的操作 * @return {[type]} [description] */ reset:function(){ this.list = []; this.index = 0; }, /** * 当破坏原来队列时,需要对队列进行修改, * index开始的所有存储值都没有用了 * @param {[type]} index [description] * @return {[type]} [description] */ splice:function(index){ this.list.splice(index); }, /** * 撤销操作 * @return {[type]} [description] */ undo:function(){ if(this.canUndo()){ this.list[this.index].undo(); this.index--; _.isFunction(this.options.afterUndo) && this.options.afterUndo(this.canUndo(),this.canRedo()); } }, /** * 重做操作 * @return {[type]} [description] */ redo:function(){ if(this.canRedo()){ this.index++; this.list[this.index].redo(); _.isFunction(this.options.afterRedo) && this.options.afterRedo(this.canUndo(),this.canRedo()); } }, canUndo:function(){ return this.index !== -1; }, canRedo:function(){ return this.list.length - 1 !== this.index; } } return mutation;
每次在使用redo或者undo时,只需要判断当前是否是队列的尾端或者起始端,再确定是否redo或者undo就可以了.
调用时的undo()
和redo()
通过传参,将不同的函数封装进队列里,就可以减少耦合度.
放大缩小
这里想了想还是记录一下,方法采用了最简单的mousedown
和mousemove
,让元素在节流中动态的变化大小,就可以了,
只需要用一个节点,在点击元素时,根据元素的大小来确定该辅助节点四个点的位置,就可以了,只要监听了这四个点的位置,再同步给该定位元素,就能实现这一效果,方法就不贴了,没有太多东西
Zusammenfassung
Ich persönlich finde dieses Projekt sehr interessant. Ich kann neue Algorithmen erlernen und neue Datenstrukturen verstehen, die ich auch in das Middleware-Modell eingefügt habe und das Publish-Subscriber-Modell hat mir ein neues Verständnis von js gegeben. Obwohl require zum Verwalten von Modulen verwendet wurde, ist die Struktur immer noch stark gekoppelt und sollte immer noch eingeschränkt sein.
Als Rücktritt zum letzten Projekt zuvor dass sich meine Programmierfähigkeiten seit Anfang des Jahres immer noch nicht wesentlich verändert haben. Vielleicht ist es an der Zeit, mich von der komfortablen Umgebung zu lösen und von vorne zu beginnen
Das obige ist der detaillierte Inhalt vonZusammenfassung der jsPlumb-Flussdiagramm-Erfahrung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen



In unseren Arbeitsbesprechungen verwenden wir häufig Flussdiagramme. Die Verwendung von Flussdiagrammen kann Erklärungen intuitiver und bequemer machen. Tatsächlich ist es nicht schwierig, ein Flussdiagramm zu erstellen. Sie können lediglich ein WPS-Dokument erstellen. Der nachfolgende Editor erklärt Ihnen die konkreten Schritte zum Zeichnen eines Flussdiagramms in einem WPS-Dokument: 1. Wir öffnen die WPS-Software und wählen in der Menüleiste die Schaltfläche Einfügen. 2. Wir wählen das abgerundete Rechteck des Flussdiagramms aus und zeichnen es auf der Seite. Im Inneren befinden sich verschiedene Flussdiagramme und Pfeilmuster. Wählen Sie einfach eines davon aus und ziehen Sie es in das Dokument. Klicken Sie dann mit der rechten Maustaste, um Text hinzuzufügen, und geben Sie Text ein. 3. Zu diesem Zeitpunkt stellten wir fest, dass der gezeichnete rechteckige Rahmen solide war, und setzten ihn im Zeichenwerkzeug zurück, um ihn mit einer transparenten Farbe zu füllen. 4. Klicken wir auf dieses rechteckige Feld und verwenden Sie die Maus

So implementieren Sie mit WebSocket und JavaScript ein Online-Spracherkennungssystem. Einführung: Mit der kontinuierlichen Weiterentwicklung der Technologie ist die Spracherkennungstechnologie zu einem wichtigen Bestandteil des Bereichs der künstlichen Intelligenz geworden. Das auf WebSocket und JavaScript basierende Online-Spracherkennungssystem zeichnet sich durch geringe Latenz, Echtzeit und plattformübergreifende Eigenschaften aus und hat sich zu einer weit verbreiteten Lösung entwickelt. In diesem Artikel wird erläutert, wie Sie mit WebSocket und JavaScript ein Online-Spracherkennungssystem implementieren.

WebSocket und JavaScript: Schlüsseltechnologien zur Realisierung von Echtzeit-Überwachungssystemen Einführung: Mit der rasanten Entwicklung der Internet-Technologie wurden Echtzeit-Überwachungssysteme in verschiedenen Bereichen weit verbreitet eingesetzt. Eine der Schlüsseltechnologien zur Erzielung einer Echtzeitüberwachung ist die Kombination von WebSocket und JavaScript. In diesem Artikel wird die Anwendung von WebSocket und JavaScript in Echtzeitüberwachungssystemen vorgestellt, Codebeispiele gegeben und deren Implementierungsprinzipien ausführlich erläutert. 1. WebSocket-Technologie

Einführung in die Verwendung von JavaScript und WebSocket zur Implementierung eines Online-Bestellsystems in Echtzeit: Mit der Popularität des Internets und dem Fortschritt der Technologie haben immer mehr Restaurants damit begonnen, Online-Bestelldienste anzubieten. Um ein Echtzeit-Online-Bestellsystem zu implementieren, können wir JavaScript und WebSocket-Technologie verwenden. WebSocket ist ein Vollduplex-Kommunikationsprotokoll, das auf dem TCP-Protokoll basiert und eine bidirektionale Kommunikation zwischen Client und Server in Echtzeit realisieren kann. Im Echtzeit-Online-Bestellsystem, wenn der Benutzer Gerichte auswählt und eine Bestellung aufgibt

So implementieren Sie ein Online-Reservierungssystem mit WebSocket und JavaScript. Im heutigen digitalen Zeitalter müssen immer mehr Unternehmen und Dienste Online-Reservierungsfunktionen bereitstellen. Es ist von entscheidender Bedeutung, ein effizientes Online-Reservierungssystem in Echtzeit zu implementieren. In diesem Artikel wird erläutert, wie Sie mit WebSocket und JavaScript ein Online-Reservierungssystem implementieren, und es werden spezifische Codebeispiele bereitgestellt. 1. Was ist WebSocket? WebSocket ist eine Vollduplex-Methode für eine einzelne TCP-Verbindung.

JavaScript und WebSocket: Aufbau eines effizienten Echtzeit-Wettervorhersagesystems Einführung: Heutzutage ist die Genauigkeit von Wettervorhersagen für das tägliche Leben und die Entscheidungsfindung von großer Bedeutung. Mit der Weiterentwicklung der Technologie können wir genauere und zuverlässigere Wettervorhersagen liefern, indem wir Wetterdaten in Echtzeit erhalten. In diesem Artikel erfahren Sie, wie Sie mit JavaScript und WebSocket-Technologie ein effizientes Echtzeit-Wettervorhersagesystem aufbauen. In diesem Artikel wird der Implementierungsprozess anhand spezifischer Codebeispiele demonstriert. Wir

JavaScript-Tutorial: So erhalten Sie HTTP-Statuscode. Es sind spezifische Codebeispiele erforderlich. Vorwort: Bei der Webentwicklung ist häufig die Dateninteraktion mit dem Server erforderlich. Bei der Kommunikation mit dem Server müssen wir häufig den zurückgegebenen HTTP-Statuscode abrufen, um festzustellen, ob der Vorgang erfolgreich ist, und die entsprechende Verarbeitung basierend auf verschiedenen Statuscodes durchführen. In diesem Artikel erfahren Sie, wie Sie mit JavaScript HTTP-Statuscodes abrufen und einige praktische Codebeispiele bereitstellen. Verwenden von XMLHttpRequest

Verwendung: In JavaScript wird die Methode insertBefore() verwendet, um einen neuen Knoten in den DOM-Baum einzufügen. Diese Methode erfordert zwei Parameter: den neuen Knoten, der eingefügt werden soll, und den Referenzknoten (d. h. den Knoten, an dem der neue Knoten eingefügt wird).
