const Text_Font_Height = 14 const Color = Object.freeze({ BLACK: "black", BLUE: "blue", GREEN: "green", RED: "red", WHITE: "rgba(255,255,255)", SHADOW: "rgba(130,130,130)", EDGE_INVISIBLE: "#999999", NOTE_BACKGROUND: "#FCFC9F", }) const Edge_Type = Object.freeze({ INVISIBLE: "invisible", NORMAL: "normal", }) const Mode = Object.freeze({ FOCUS: "Focus", REFERENCES: "References", FORWARD_REFERENCES: "Forward_References", BACKWARD_REFERENCES: "Backward_References", ALL_REFERENCES: "All_References", REMOVE_NODE: "Remove_Node", REMOVE_EDGE: "Remove_Edge", OPEN: "Open", }) /* * Render Data into a Data_List */ class Data_List_Class { constructor(Data_List_Element) { this.Data_List_Element = Data_List_Element } Remove_all_Children() { const Last_Index = this.Data_List_Element.options.length - 1 for (let Index = Last_Index; Index >= 0; Index--) { this.Data_List_Element.children[Index].remove() } } Fill_with_Numbers(Number_List) { this.Remove_all_Children() for (const Dings_Number of Number_List) { const Option_Element = document.createElement("option") Option_Element.textContent = Dings_Number this.Data_List_Element.appendChild(Option_Element) } } Fill_with_Names(Name_List) { this.Remove_all_Children() for (const Dings_Name of Name_List) { const Option_Element = document.createElement("option") Option_Element.textContent = Dings_Name this.Data_List_Element.appendChild(Option_Element) } } } /* * Render Name Data and resolve Dings_Number */ class Name_Data_List_Class { constructor(Data_List_Element, Flex_Index_Global_Mapping) { this.Data_List_View = new Data_List_Class(Data_List_Element) this.Flex_Index_Global_Mapping = Flex_Index_Global_Mapping this.Name_to_Number_Dict = {} } Get_Name_Data(Result_List) { const Name_List = [] const Name_To_Number_Dict = {} for (const Mapping_Index of Result_List) { const Dings_Number = this.Flex_Index_Global_Mapping[Mapping_Index][0] let Dings_Name = this.Flex_Index_Global_Mapping[Mapping_Index][1] Dings_Name += " (" + Dings_Number + ")" Name_List.push(Dings_Name) Name_To_Number_Dict[Dings_Name] = Dings_Number } return { Name_List: Name_List, Name_To_Number_Dict: Name_To_Number_Dict, } } Fill_with_Result_List(Result_List) { const Name_Data = this.Get_Name_Data(Result_List) this.Name_to_Number_Dict = Name_Data.Name_To_Number_Dict this.Data_List_View.Fill_with_Names(Name_Data.Name_List) } Get_Dings_Number(Dings_Name) { return this.Name_to_Number_Dict[Dings_Name] } } const Mouse_State = Object.freeze({ IDLE: "Idle", DOWN: "Down", DRAGGING: "Dragging", }) /* * Store Mouse State for Canvas Interaction */ class Mouse_State_Class { constructor() { this.Dragged_Node = null this.State = Mouse_State.IDLE } Set_Down(Nearest) { this.Dragged_Node = Nearest this.State = Mouse_State.DOWN } Set_Dragging() { this.State = Mouse_State.DRAGGING } Set_Idle() { this.Dragged_Node = null this.State = Mouse_State.IDLE } Is_Down() { return this.State == Mouse_State.DOWN || this.State == Mouse_State.DRAGGING } Is_Click() { return this.State == Mouse_State.DOWN } } /* * Allow Navigation in Dings-Objects */ class Dings_Navigator_Class extends Dings_App_Class { Get_Best_Existing_Node(Node_Name) { if (!Node_Name) return false let Parts = Node_Name.split(".") for (let i = Parts.length; i > 0; i--) { let Candidate = Parts.slice(0, i).join(".") let Node = this.Sys.getNode(Candidate) if (Node) return Node } return false } // Breadth-First-Search Get_Nodes_Within_Distance(Start_Node, Max_Distance) { let Visited = new Set() let Queue = [[Start_Node, 0]] while (Queue.length > 0) { let [Node, Distance] = Queue.shift() if (Distance <= Max_Distance) { Visited.add(Node) for (let Neighbor of this.Dings_Json.Dings_List[Node].Neighbours) { Queue.push([Neighbor, Distance + 1]) } } } return Array.from(Visited) } // Test-Function Test() { let Node_List = this.Get_Nodes_Within_Distance("10000085", 2) console.log("TEST") console.log(Node_List) } // Start Timer for freezing Simulation Start_Timer() { const Sys = this.Sys Sys.start() window.setTimeout(function() { console.log("Timeout") Sys.stop() }, 3000) } // Clear all Nodes Prune_Nodes() { if (!this.Node_Center) { console.log("Prune: No Center-Node") this.Sys.prune(function(Node){return true}) this.Node_Count = 0 this.Node_Map = {} return } console.log("Prune: " + this.Node_Center.name) this.Sys.prune(function(Node){return true}) this.Node_Count = 0 this.Node_Map = {} } Init_Particle_System() { this.Sys = arbor.ParticleSystem({ repulsion: 1000, stiffness: 400, friction: 1, gravity: true, fps: 40}) // this.Sys.parameters({gravity:true}) this.Sys.renderer = this.Renderer this.Sys.Dings_Navigator = this } Add_Node(Node_Name) { // console.log("Node-Count: " + this.Node_Count) if (this.Node_Count >= this.Node_Count_Max) return false if (this.Node_Map[Node_Name] != undefined) return this.Node_Map[Node_Name] const Node_Current = this.Sys.getNode(Node_Name) if (Node_Current != undefined) { this.Node_Map[Node_Name] = Node_Current return Node_Current } this.Node_Count += 1 console.log("Name: " + Node_Name) const Dings_Number = this.Dings_Number_From_Node_Name(Node_Name) const Dings = this.Get_Dings_By_Number(Dings_Number) const Dings_Link = Dings_Number + ".html" this.Flex_Index_Local.add(Dings_Number, Dings.Name) console.log("Add Node: " + Node_Name) const Node = this.Sys.addNode(Node_Name, {mass:2, 'color':Color.BLUE,'shape':'dot','label':Dings.Name, dings_number:Dings_Number, link:Dings_Link, type:'Human', Navigator:this}) this.Node_Map[Node_Name] = Node return Node } Remove_Node(Node_Name) { this.Sys.pruneNode(Node_Name) delete this.Node_Map[Node_Name] this.Node_Count -= 1 this.Switch_Center_Node_Locked = false this.Node_Center = false } Get_Nearest_Node(Point) { return this.Sys.nearest(Point).node } // https://github.com/scottglz/distance-to-line-segment Distance_Squared_to_Line_Segment_2(Point, Point_1, D_X, D_Y, Line_Length_Squared) { let t // t===0 at line pt 1 and t===1 at line pt 2 if (!Line_Length_Squared) { // 0-length line segment. Any t will return same result t = 0 } else { t = ((Point.x - Point_1.x) * D_X + (Point.y - Point_1.y) * D_Y) / Line_Length_Squared if (t < 0) t = 0 else if (t > 1) t = 1 } const Line_X = Point_1.x + t * D_X const Line_Y = Point_1.y + t * D_Y const D_Point_X = Point.x - Line_X const D_Point_Y = Point.y - Line_Y return D_Point_X * D_Point_X + D_Point_Y * D_Point_Y } // Distance_Squared_to_Line_Segment(lx1, ly1, lx2, ly2, px, py) { Distance_Squared_to_Line_Segment(Point, Point_1, Point_2) { const D_X = Point_2.x - Point_1.x const D_Y = Point_2.y - Point_1.y const Line_Length_Squared = D_X * D_X + D_Y * D_Y return this.Distance_Squared_to_Line_Segment_2(Point, Point_1, D_X, D_Y, Line_Length_Squared) } // Get Distance of Point to Edge (Point_1 -> Point_2) Get_Distance_From_Edge(Point, Point_1, Point_2) { return Math.sqrt(this.Distance_Squared_to_Line_Segment(Point, Point_1, Point_2)) } Get_Nearest_Edge(Point, Selected_Node=false) { let Nearest_Distance let Nearest_Edge = false this.Sys.eachEdge(function(Edge, Point_1, Point_2) { if (Edge.data.type == Edge_Type.INVISIBLE) return false // var Distance = Edge.data.Navigator.Get_Distance_From_Edge(Point, Edge) if (Selected_Node && Selected_Node.name != Edge.source.name) return false const Distance = Edge.data.Navigator.Get_Distance_From_Edge(Point, Point_1, Point_2) if (!Nearest_Edge || Distance < Nearest_Distance) { Nearest_Distance = Distance Nearest_Edge = Edge } }) return Nearest_Edge } Add_Edge(Node_Name_Source, Node_Name_Target) { if (Node_Name_Source == Node_Name_Target) return false if (this.Sys.getEdges(Node_Name_Source, Node_Name_Target).length != 0) return false if (!this.Node_Map[Node_Name_Source]) return false if (!this.Node_Map[Node_Name_Target]) return false return this.Sys.addEdge(Node_Name_Source, Node_Name_Target, {'color':Color.BLACK, 'type': Edge_Type.NORMAL, Navigator:this}) } Process_Locked(Node_Center) { if (!this.Node_Last_Clicked || this.Node_Last_Clicked.name != Node_Center.name) { console.log(" -no") this.Node_Last_Clicked = Node_Center this.Switch_Center_Node_Locked = false return false } if (this.Switch_Center_Node_Locked) { Node_Center.data.color = Color.BLUE this.Switch_Center_Node_Locked = false } else { this.Switch_Center_Node_Locked = Node_Center Node_Center.data.color = Color.GREEN } return true } Get_Statement_List_For_Dings(Dings_Number) { const Dings = this.Get_Dings_By_Number(Dings_Number) if (!Dings) return [] if (!Dings.Statements) return [] if (!Array.isArray(Dings.Statements)) return [] return Dings.Statements } Has_Self_Target_Statement(Dings_Number) { const Dings_Number_String = String(Dings_Number) for (const Statement of this.Get_Statement_List_For_Dings(Dings_Number_String)) { if (!Statement || !Statement.Object_Target) continue if (String(Statement.Object_Target) == Dings_Number_String) return true } return false } Get_Legacy_Target_Node_Name(Center_Node, Target_Number) { return Center_Node.name + "." + String(Target_Number) } Apply_Statement_Labels_To_Loaded_Graph() { console.log("XXX Apply_Statement_Labels_To_Loaded_Graph") if (!this.Node_Center) return const Dings_Number = this.Dings_Number_From_Node_Name(this.Node_Center.name) const Statement_List = this.Get_Statement_List_For_Dings(Dings_Number) if (!Statement_List.length) return console.log(" - XXX Apply_Statement_Labels_To_Loaded_Graph") for (const Statement of Statement_List) { if (!Statement || !Statement.Object_Target) continue const Legacy_Node_Name = this.Get_Legacy_Target_Node_Name(this.Node_Center, Statement.Object_Target) let Node_Name = Legacy_Node_Name console.log(" - XXX Legacy_Node_Name: " + Legacy_Node_Name) if (!this.Node_Map[Node_Name]) Node_Name = this.Get_Statement_Target_Node_Name(this.Node_Center, Statement) if (this.Node_Map[Node_Name] && Statement.Object_Text) this.Node_Map[Node_Name].data.label = Statement.Object_Text if (Statement.Dsl) { const Edge_Name = this.Node_Center.name + "_" + Node_Name if (this.Edge_Map && this.Edge_Map[Edge_Name] && this.Edge_Map[Edge_Name].data) this.Edge_Map[Edge_Name].data.label = Statement.Dsl } } } Get_Statement_Target_Node_Name(Center_Node, Statement) { const Dings_Number_Center = String(this.Dings_Number_From_Node_Name(Center_Node.name)) const Target_Number = String(Statement.Object_Target) let Node_Name = Center_Node.name + "." + Target_Number if (Target_Number == Dings_Number_Center) Node_Name += "@" + String(Statement.Line) return Node_Name } Add_Target_References_From_Statements(Center_Node) { console.log("XXX ADD Statement") const Dings_Number = this.Dings_Number_From_Node_Name(Center_Node.name) const Statement_List = this.Get_Statement_List_For_Dings(Dings_Number) if (!Statement_List.length) return false for (const Statement of Statement_List) { console.log(Statement) if (!Statement || !Statement.Object_Target) continue const Node_Name = this.Get_Statement_Target_Node_Name(Center_Node, Statement) const New_Node = this.Add_Node(Node_Name) if (!New_Node) continue if (Statement.Object_Text) New_Node.data.label = Statement.Object_Text this.Add_Edge(Center_Node.name, New_Node.name) } return true } Get_Statements_Html(Node_Center, Node_Target) { const Dings_Number = this.Dings_Number_From_Node_Name(Node_Center.name) const Dings_Number_Target = this.Dings_Number_From_Node_Name(Node_Target.name) const Target_List = this.Dings_Json.Dings_List[Dings_Number].Targets const Line_Dict = this.Dings_Json.Dings_List[Dings_Number].Lines const Statement_Written_Dict = {} // Get List of Line-Numbers const Line_Number_List = [] var Line_Number var Target_Number for (const Target of Target_List) { Target_Number = Target[0] if (Dings_Number_Target != Target_Number) continue Line_Number = Target[1] Line_Number_List.push(Line_Number) } const Label_List = [] for (const Target of Target_List) { Target_Number = Target[0] Line_Number = Target[1] if (!Line_Number_List.includes(Line_Number)) continue // if (Line_Number == 2) // continue var Target_Node = this.Sys.getNode(Target_Number) if (Target_Node) { Target_Node.data.color = Color.GREEN this.Target_Node_List.push(Target_Node) } if (Statement_Written_Dict[Line_Number] !== undefined) continue Statement_Written_Dict[Line_Number] = true let Statement_Html = Line_Dict[Line_Number] const Reg_Exp = /\[([^[\]]+)\]\(\d+\.md\)/g // Statement_Html = Statement_Html.replace(/(.*)\[(\w+)\]\((\w+)\.md\)(.*)/, "$1$2$4") Statement_Html = Statement_Html.replace(Reg_Exp, "\[$1\]") Statement_Html = Statement_Html.replace(/^(\- )/,"") Label_List.push(Statement_Html) } return Label_List } Dings_Number_From_Node_Name(Node_Name) { if (!Node_Name.includes(".")) { return Node_Name } const Node_Name_Element_List = Node_Name.split(".") const Node_Name_Last = Node_Name_Element_List[Node_Name_Element_List.length - 1] if (Node_Name_Last.includes("@")) return Node_Name_Last.split("@")[0] return Node_Name_Last } Switch_Center_Edge(Edge) { for (var Target_Node of this.Target_Node_List) { Target_Node.data.color = Color.BLUE } this.Target_Node_List = [] if (this.Edge_Center != undefined) { this.Edge_Center.data.color = Color.BLACK this.Edge_Center.data.Label_List = false if (!Edge) return } if (Edge) { Edge.data.color = Color.RED Edge.data.Label_List = this.Get_Statements_Html(Edge.source, Edge.target) } this.Edge_Center = Edge } Switch_Center_Node(Node_Name) { console.log("XXX Switch_Center_Node: " + Node_Name) if (this.Switch_Center_Node_Locked) return const Dings_Number_From_Node_Name = this.Dings_Number_From_Node_Name const Dings_Number_Center_New = Dings_Number_From_Node_Name(Node_Name) console.log(" - Dings-Number: " + Dings_Number_Center_New) /* Check for Dings with Access-File (TBD) */ const Dings = this.Get_Dings_By_Number(Dings_Number_Center_New) if (!Dings) { this.Dings_Number_Input.value = Dings_Number_Center_New this.Dings_Name_Input.value = "" if (this.Dings_Definition) this.Dings_Definition.innerHTML = "" return } const Dings_Name = this.Dings_Json.Dings_List[Dings_Number_Center_New].Name this.Dings_Number_Input.value = Dings_Number_Center_New this.Dings_Name_Input.value = Dings_Name this.Dings_Definition.innerHTML = this.Dings_Json.Dings_List[Dings_Number_Center_New].Definition if (this.Node_Center) { const Dings_Number_Center_Old = Dings_Number_From_Node_Name(this.Node_Center.name) this.Sys.eachNode(function(Node, Pt) { if (Dings_Number_From_Node_Name(Node.name) == Dings_Number_Center_Old) Node.data.color = Color.BLUE }) } this.Sys.eachNode(function(Node, Pt) { if (Dings_Number_From_Node_Name(Node.name) == Dings_Number_Center_New) Node.data.color = Color.RED }) this.Node_Center = this.Node_Map[Node_Name] } Add_Backward_References(Node_Center) { console.log("Add Backward: " + Node_Center.name) const Dings_Number_Center = this.Dings_Number_From_Node_Name(Node_Center.name) const Reference_List = this.Dings_Json.Dings_List[Dings_Number_Center].Sources for (const Dings_Number of Reference_List) { /* Check for Dings with Access-File (TBD) */ const Source_Dings = this.Get_Dings_By_Number(Dings_Number) if (!Source_Dings) { console.log("Skip unloaded backward Dings: " + Dings_Number) continue } const Source_Name = Dings_Number.toString() if ((String(Dings_Number) == String(Dings_Number_Center)) && this.Has_Self_Target_Statement(Dings_Number_Center)) continue if (Dings_Number == 17) // XXX FIXME continue const Source_Node = this.Add_Node(Node_Center.name + "." + Source_Name) if (!Source_Node) break this.Add_Edge(Source_Node.name, Node_Center.name) } } Get_Dings_By_Number(Dings_Number) { if (!(Dings_Number in this.Dings_Json.Dings_List)) return false if (this.Dings_Json.Dings_List[Dings_Number] === undefined) return false return this.Dings_Json.Dings_List[Dings_Number] } Get_Child_Dict(Dings_Number, Child_Dict, Level) { if (Level == 0) return console.log("get child : " + Dings_Number) const Dings = this.Get_Dings_By_Number(Dings_Number) if (!Dings) return console.log(" - get child: " + Dings_Number) for (const Child_Number of Dings.Childs) { Child_Dict[Child_Number] = Child_Number this.Get_Child_Dict(Child_Number, Child_Dict, Level - 1) } } Filter_Parent(Dings_Number_Parent) { const Dings_Number_From_Node_Name = this.Dings_Number_From_Node_Name const Dings_List = this.Dings_Json.Dings_List const Sys = this.Sys const Search_Dict = {} Search_Dict[Dings_Number_Parent] = Dings_Number_Parent this.Get_Child_Dict(Dings_Number_Parent, Search_Dict, 3) for (const [Dings_Number, Dings] of Object.entries(Search_Dict)) { const Dings_Found = this.Get_Dings_By_Number(Dings_Number) if (!Dings_Found) continue console.log(" Filter -> " + Dings_Found.Name) } const Remove_Node_List = [] Sys.eachNode(function(Node, Pt) { const Dings_Number = Dings_Number_From_Node_Name(Node.name) if (!(Dings_Number in Search_Dict)) { console.log(" Filter: " + Dings_Number) Remove_Node_List.push(Node) } }) for (const Node of Remove_Node_List) { if (this.Switch_Center_Node_Locked && Node.name == this.Switch_Center_Node_Locked.name) continue this.Remove_Node(Node.name) } this.Dings_Type_Name_Input.value = Dings_List[Dings_Number_Parent].Name this.Dings_Type_Number_Input.value = Dings_Number_Parent } Switch_to_Node(Node_Name) { const Dings_Number = this.Dings_Number_From_Node_Name(Node_Name) let Mode_Current = this.Select_Mode.value console.log("Switch_to_Node") console.log(" - Mode : " + Mode_Current) console.log(" - Node : " + Node_Name) console.log(" - Number: " + Dings_Number) if (Mode_Current == Mode.OPEN) { const Dings_Link = Dings_Number + ".html" // XXX window.open(Dings_Link, "_blank") // XXX return } this.History_Before_State_Change() if (Mode_Current == Mode.REMOVE_NODE) { this.Remove_Node(Node_Name) this.History_After_State_Change() return } if (Mode_Current == Mode.FOCUS) { this.Focus_Dings_Number = Dings_Number this.Prune_Nodes() Mode_Current = Mode.ALL_REFERENCES } const Node_Center = this.Add_Node(Node_Name) this.Node_Center = Node_Center this.Switch_Center_Node(Node_Name) // Add new Nodes if (Mode_Current == Mode.FORWARD_REFERENCES || Mode_Current == Mode.ALL_REFERENCES) { this.Add_Target_References_From_Statements(Node_Center) } if (Mode_Current == Mode.BACKWARD_REFERENCES || Mode_Current == Mode.ALL_REFERENCES) { this.Add_Backward_References(Node_Center) } this.Dings_Number_Input.value = Dings_Number this.History_After_State_Change() } Load_Json(Json) { for (const Node_Name of Json.Node_List) { console.log("XXX add: " + Node_Name) this.Add_Node(Node_Name) } for (const Edge_List_Entry of Json.Edge_List) { this.Add_Edge(Edge_List_Entry[0], Edge_List_Entry[1]) } if (Json.Center_Node) { const Center_Node_Name = String(Json.Center_Node) this.Focus_Dings_Number = false this.Node_Last_Clicked = false this.History_Current_State_Dict = false this.History_Current_State_String = false const Dings_Number = this.Dings_Number_From_Node_Name(Center_Node_Name) const Dings = this.Get_Dings_By_Number(Dings_Number) this.Focus_Dings_Number = Dings_Number console.log("Set Center-Node: " + Center_Node_Name) this.Dings_Number_Input.value = Dings_Number this.Dings_Name_Input.value = Dings.Name console.log("XXX: " + Center_Node_Name) console.log("XXX: " + Dings_Number) const Center_Node = this.Node_Map[Center_Node_Name] if (!Center_Node) { console.log("ERROR: Center_Node not found: " + Center_Node_Name) console.log("Available Nodes: " + Object.keys(this.Node_Map).join(", ")) // return } this.Node_Last_Clicked = Center_Node this.Node_Center = Center_Node console.log("XXX Center_Node:", Center_Node_Name) console.log("XXX Node_List contains Center:", Json.Node_List.includes(Center_Node_Name)) console.log("XXX Node_Map:", Center_Node) Center_Node.data.color = Color.GREEN this.Switch_Center_Node(Center_Node_Name) // Initial load still reuses the already loaded graph. Apply Statement // aliases afterwards, so legacy target nodes like "
." // immediately show Object_Text such as "DSL" before the first click. this.Apply_Statement_Labels_To_Loaded_Graph() // Refresh once more after relabeling, so the UI inputs / overlays stay // in sync with the updated node labels. this.Switch_Center_Node(Center_Node_Name) } console.log("Center-Node: " + Json.Center_Node) } Get_Canvas_Screenshot() { const Canvas = document.getElementById(this.Html_Id + "." + "viewport") let Data_Url = Canvas.toDataURL("image/png") /* Change MIME type to trick the browser to downlaod the file instead of displaying it */ Data_Url = Data_Url.replace(/^data:image\/[^;]*/, 'data:application/octet-stream') /* In addition to 's "download" attribute, you can define HTTP-style headers */ Data_Url = Data_Url.replace(/^data:application\/octet-stream/, 'data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=Canvas.png') return Data_Url } Get_Polygon_From_Line(Line_X1, Line_Y1, Line_X2, Line_Y2, Polygon_Width) { // Calculate the Vectors for the Line const D_X = Line_X2 - Line_X1 const D_Y = Line_Y2 - Line_Y1 // Normalize the Vectors const Length = Math.sqrt(D_X * D_X + D_Y * D_Y) const N_X = D_X / Length const N_Y = D_Y / Length // Calculate the Vectors for the Polygon-Edges const Offset_X = N_X * Polygon_Width / 2 const Offset_Y = N_Y * Polygon_Width / 2 // Calculate the Coordinates for the Polygon-Points const Polygon_X1 = Math.round(Line_X1 + Offset_Y) const Polygon_Y1 = Math.round(Line_Y1 - Offset_X) const Polygon_X2 = Math.round(Line_X1 - Offset_Y) const Polygon_Y2 = Math.round(Line_Y1 + Offset_X) const Polygon_X3 = Math.round(Line_X2 - Offset_Y) const Polygon_Y3 = Math.round(Line_Y2 + Offset_X) const Polygon_X4 = Math.round(Line_X2 + Offset_Y) const Polygon_Y4 = Math.round(Line_Y2 - Offset_X) // Return the Polygon-Points as List return [ Polygon_X1, Polygon_Y1, Polygon_X2, Polygon_Y2, Polygon_X3, Polygon_Y3, Polygon_X4, Polygon_Y4 ] } Get_Image_Map() { const Canvas = document.getElementById(this.Html_Id + "." + "viewport") const Context = Canvas.getContext("2d") console.log("Canvas: " + Canvas.clientWidth + " / " + Canvas.width) let Image_Map = "{" Image_Map += '\t"Title": "Test",\n' Image_Map += '\t"Image": "305001054.png",\n' Image_Map += '\t"Map_List": [\n' let First_Node = true const Dings_Number_From_Node_Name = this.Dings_Number_From_Node_Name const Margin = 2 this.Sys.eachNode(function(Node, Point) { const Label = Node.data.label const Text_Width = Context.measureText(Label).width + 6 const Dings_Number = Dings_Number_From_Node_Name(Node.name) Point.x = Math.floor(Point.x) Point.y = Math.floor(Point.y) if (First_Node) First_Node = false else Image_Map += ',\n' Image_Map += '\t\t{\n' Image_Map += `\t\t\t"Type": "Rectangle",\n` Image_Map += `\t\t\t"Text": "${Label}",\n` Image_Map += `\t\t\t"Dings_Number": "${Dings_Number}",\n` Image_Map += `\t\t\t"Color": "rgba(20,255,14,0.4)",\n` Image_Map += `\t\t\t"Left_Top_X": "${Point.x - Text_Width / 2 - Margin}",\n` Image_Map += `\t\t\t"Left_Top_Y": "${Point.y - Text_Font_Height / 2 - Margin}",\n` Image_Map += `\t\t\t"Width": "${Text_Width + Margin * 2}",\n` Image_Map += `\t\t\t"Height": "${Text_Font_Height + Margin * 2}"\n` Image_Map += '\t\t}' }) this.Sys.eachEdge(function(Edge, Point_1, Point_2) { if (First_Node) First_Node = false else Image_Map += ',\n' Image_Map += '\t\t{\n' Image_Map += `\t\t\t"Type": "Polygon",\n` Image_Map += `\t\t\t"Text": "Test Line",\n` Image_Map += `\t\t\t"Dings_Number": "404",\n` Image_Map += `\t\t\t"Color": "rgba(20,255,14,0.4)",\n` const Head_Length = 10 // Length of Head in Pixels const X_1 = Point_1.x const Y_1 = Point_1.y const D_X = (Point_2.x - Point_1.x) * 0.9 const D_Y = (Point_2.y - Point_1.y) * 0.9 const X_2 = Point_1.x + D_X const Y_2 = Point_1.y + D_Y const Angle = Math.atan2(D_Y, D_X) Image_Map += '\t\t\t"Polygon_List": [[' let First = true for (const Coordinate of this.Get_Polygon_From_Line(X_1, Y_1, X_2, Y_2, 5)) { if (First) First = false else Image_Map += ', ' Image_Map += `${Coordinate}` } Image_Map += ']]\n' Image_Map += '\t\t}' /* Context.moveTo(Point_1.x, Point_1.y) Context.lineTo(x2, y2) Context.lineTo(x2 - Head_Length * Math.cos(Angle - Math.PI / 6), y2 - Head_Length * Math.sin(Angle - Math.PI / 6)) Context.moveTo(x2, y2) Context.lineTo(x2 - Head_Length * Math.cos(Angle + Math.PI / 6), y2 - Head_Length * Math.sin(Angle + Math.PI / 6)) if (Edge.data.Label_List) { Edge_With_Label = Edge Label_X = (Point_1.x + Point_2.x) /2 Label_Y = (Point_1.y + Point_2.y) /2 } Context.stroke() */ }.bind(this)) Image_Map += '\n' Image_Map += '\t]\n' Image_Map += '}\n' return Image_Map } Get_Node_List() { const Node_List = [] this.Sys.eachNode(function(Node, Point) { const Node_Name = Node.name Node_List.push(Node_Name) }) return Node_List } Get_Edge_List() { const Edge_List = [] this.Sys.eachEdge(function(Edge, Point_1, Point_2) { const Node_Name_Source = Edge.source.name const Node_Name_Target = Edge.target.name Edge_List.push([Node_Name_Source, Node_Name_Target]) }) return Edge_List } Get_State_Dict() { let Center_Node_Name = false if (this.Node_Last_Clicked && this.Node_Last_Clicked.name) Center_Node_Name = this.Node_Last_Clicked.name else if (this.Node_Center && this.Node_Center.name) Center_Node_Name = this.Node_Center.name console.log("Get_State_Dict Center-Node: " + Center_Node_Name) if (this.Select_Mode.value == Mode.FOCUS) { let Center_Dings_Number = this.Focus_Dings_Number console.log("Get_State_Dict Focus-Dings-Number: " + Center_Dings_Number) return { "State_Mode" : Mode.FOCUS, "Center_Node" : Center_Dings_Number } } return { "State_Mode" : this.Select_Mode.value, "Center_Node" : Center_Node_Name, "Node_List" : this.Get_Node_List(), "Edge_List" : this.Get_Edge_List() } } Get_Navigator_Dict() { let Center_Node_Name = false if (this.Node_Last_Clicked && this.Node_Last_Clicked.name) Center_Node_Name = this.Node_Last_Clicked.name else if (this.Node_Center && this.Node_Center.name) Center_Node_Name = this.Node_Center.name if (Center_Node_Name !== false) Center_Node_Name = this.Dings_Number_From_Node_Name(String(Center_Node_Name)) return { "Center_Node" : Center_Node_Name, "Node_List" : this.Get_Node_List(), "Edge_List" : this.Get_Edge_List() } } Apply_State_Dict(State_Dict) { if (State_Dict.State_Mode == Mode.FOCUS && State_Dict.Center_Node) { this.Select_Mode.value = Mode.FOCUS this.Switch_to_Node(String(State_Dict.Center_Node)) return } this.Prune_Nodes() this.Load_Json(State_Dict) } Get_Json() { return JSON.stringify(this.Get_Navigator_Dict(), null, 4) } Download_Url(Url, File_Name) { const Link = document.createElement('a') Link.href = Url Link.download = File_Name document.body.appendChild(Link) Link.click() document.body.removeChild(Link) window.URL.revokeObjectURL(Url) } Download_File(File_Contents, File_Name, Mime_Type) { const File_Handle = new File([File_Contents], File_Name, { type: Mime_Type }) const Url = URL.createObjectURL(File_Handle) this.Download_Url(Url, File_Name) } Download_Image_Map_Handler = Event => { console.log("Click") this.Download_File(this.Get_Image_Map(), '305001054.image_map', 'text/plain') this.Download_Url(this.Get_Canvas_Screenshot(), '305001054.png') } Download_Json_Handler = Event => { console.log("Click") this.Download_File(this.Get_Json(), 'Dings_Navigator.txt', 'text/plain') } Result_List_Search_Name(Name, Result_Limit) { if (this.Select_Scope.value == "Global") return this.Flex_Index_Global.search(Name, Result_Limit) if (this.Select_Scope.value == "Local") return this.Flex_Index_Local.search(Name, Result_Limit) return [] } Result_List_Search_Number(Search_Number, Result_Limit) { return this.Flex_Index_Numbers.search(Search_Number, Result_Limit) } // Name-Input Name_Input_Handle_Search = Event => { this.Switch_Center_Node_Locked = false console.log("Search: " + this.Dings_Name_Input.value) console.log(" - " + this.Dings_Name_Input) console.log(Event) const Dings_Number = this.Dings_Name_Data_List_View.Get_Dings_Number(this.Dings_Name_Input.value) if (!Dings_Number) return // this.Dings_Number_Input.value = Dings_Number this.Switch_to_Node(Dings_Number) } Name_Input_Handle_Key_Up = Event => { if (Event.key === "Enter") return const Name = Event.target.value const Result_List = this.Result_List_Search_Name(Name, 256) console.log("Name : " + Name) console.log(Result_List) this.Dings_Name_Data_List_View.Fill_with_Result_List(Result_List) } // Type-Name-Input Type_Name_Input_Handle_Search = Event => { this.Switch_Center_Node_Locked = false const Dings_Number = this.Dings_Type_Name_Data_List_View.Get_Dings_Number(this.Dings_Type_Name_Input.value) this.Filter_Parent(Dings_Number) } Type_Name_Input_Handle_Key_Up = Event => { if (Event.key === "Enter") return const Name = Event.target.value console.log(Event) const Result_List = this.Result_List_Search_Name(Name, 100) console.log("XXX Item count: " + Result_List.length) this.Dings_Type_Name_Data_List_View.Fill_with_Result_List(Result_List) } // Number-Input Number_Input_Handle_Search = Event => { this.Switch_Center_Node_Locked = false const Dings_Number = Event.target.value // this.Dings_Number_Input.value = Dings_Number this.Switch_to_Node(Dings_Number) } Number_Input_Handle_Key_Up = Event => { if (Event.key === "Enter") return const Search_Number = Event.target.value console.log(Event) const Result_List = this.Result_List_Search_Number(Search_Number, 10) this.Dings_Number_Data_List_View.Fill_with_Numbers(Result_List) } // Type-Number-Input Type_Number_Input_Handle_Search = Event => { this.Switch_Center_Node_Locked = false const Dings_Number = Event.target.value if (!Dings_Number) return this.Filter_Parent(Dings_Number) } Type_Number_Input_Handle_Key_Up = Event => { if (Event.key === "Enter") return const Search_Number = Event.target.value console.log(Event) const Result_List = this.Result_List_Search_Number(Search_Number, 10) this.Dings_Type_Number_Data_List_View.Fill_with_Numbers(Result_List) } Select_Mode_Handle_Change = Event => { if (Event.target.value == Mode.REMOVE_EDGE && this.Node_Center) { this.Node_Center.data.color = Color.BLUE this.Node_Center = false } } Select_Scope_Handle_Change = Event => { } Update() { console.log("Should do Resize: " + this.Html_Id) // XXX } /* * Build Object out of Json and Html_Id for the Widget */ constructor(Dings_Json, Html_Id) { super(Dings_Json, Html_Id) const Renderer = function(Canvas) { Canvas = document.getElementById(Html_Id + "." + "viewport") const Context = Canvas.getContext("2d") let Particle_System = null const Dom = $(Canvas) // XXX const Renderer_Object = { init:function(System) { Particle_System = System Particle_System.screen({padding:[100, 60, 60, 60], // leave some space at the bottom for the param sliders step:.02}) // have the ‘camera’ zoom somewhat slowly as the graph unfolds $(window).resize(Renderer_Object.resize) Renderer_Object.resize() Renderer_Object.initMouseHandling() }, redraw:function() { if (Particle_System === null) return Context.clearRect(0,0, Canvas.width, Canvas.height) Context.beginPath() let Edge_With_Label = false let Label_X let Label_Y const Text_Size = 11 let Shadow_Pixel = 2 Particle_System.eachEdge(function(Edge, Point_1, Point_2) { Context.beginPath() Context.fillStyle = Edge.data.color Context.strokeStyle = Edge.data.color const Arrow = true if (Arrow) { const Head_Length = 10 // Length of Head in Pixels const D_X = (Point_2.x - Point_1.x) * 0.9 const D_Y = (Point_2.y - Point_1.y) * 0.9 const X_2 = Point_1.x + D_X const Y_2 = Point_1.y + D_Y const Angle = Math.atan2(D_Y, D_X) Context.moveTo(Point_1.x, Point_1.y) Context.lineTo(X_2, Y_2) Context.lineTo(X_2 - Head_Length * Math.cos(Angle - Math.PI / 6), Y_2 - Head_Length * Math.sin(Angle - Math.PI / 6)) Context.moveTo(X_2, Y_2) Context.lineTo(X_2 - Head_Length * Math.cos(Angle + Math.PI / 6), Y_2 - Head_Length * Math.sin(Angle + Math.PI / 6)) } else { Context.moveTo(Point_1.x, Point_1.y) Context.lineTo(Point_2.x, Point_2.y) } if (Edge.data.Label_List) { Edge_With_Label = Edge Label_X = (Point_1.x + Point_2.x) /2 Label_Y = (Point_1.y + Point_2.y) /2 } Context.stroke() }) Particle_System.eachNode(function(Node, Point) { const Text_Width = Context.measureText(Node.data.label).width + 6 const Label = Node.data.label Point.x = Math.floor(Point.x) Point.y = Math.floor(Point.y) // Shadow Context.fillStyle = Color.SHADOW Context.fillRect(Point.x-Text_Width / 2 + Shadow_Pixel, Point.y - Text_Font_Height / 2 + Shadow_Pixel, Text_Width, Text_Font_Height) // Box Context.fillStyle = Color.WHITE Context.fillRect(Point.x-Text_Width / 2, Point.y - Text_Font_Height / 2, Text_Width, Text_Font_Height) // Text Context.font = "bold 11px Arial" Context.textAlign = "center" Context.fillStyle = Node.data.color Context.fillText(Label, Point.x, Point.y+4) }) // Draw Edge-Label if (Edge_With_Label) { /* const svg = `
${Edge_With_Label.data.Label_List}
` const svgBlob = new Blob( [svg], { type: 'image/svg+xml;charset=utf-8' } ) const svgObjectUrl = URL.createObjectURL( svgBlob ) const tempImg = new Image() tempImg.addEventListener( 'load', function() { Context.drawImage(tempImg, Label_X, Label_Y) URL.revokeObjectURL( svgObjectUrl ) } ) tempImg.src = svgObjectUrl */ let Text_Height = 0 let Text_Width = 0 const Border_Pixel = 5 const Border_Window_Pixel = 20 const Max_Width = Canvas.clientWidth - Border_Pixel - Border_Window_Pixel const Max_Height = Canvas.clientHeight - Border_Pixel - Border_Window_Pixel Context.font = "11px Arial" Context.textAlign = "left" const Split_Lines_List = [] for (const Label of Edge_With_Label.data.Label_List) { const New_Line_List = [] if (Context.measureText(Label).width > Max_Width) { const Word_List = Label.split(" ") let New_Line = "" for (const Word of Word_List) { if (Context.measureText(New_Line + " " + Word).width > Max_Width) { New_Line_List.push(New_Line) New_Line = "" } if (New_Line != "") New_Line += " " New_Line += Word } New_Line_List.push(New_Line) } else { New_Line_List.push(Label) } Split_Lines_List.push(New_Line_List) } for (const Line of Split_Lines_List) { for (const Label of Line) { Text_Width = Math.max(Text_Width, Context.measureText(Label).width) Text_Height += Text_Size + 16 } } // Box Label_X = Math.min(Max_Width - Text_Width - Shadow_Pixel, Label_X) Label_X = Math.max(0, Label_X) Label_Y = Math.min(Max_Height - Text_Height, Label_Y) Label_Y = Math.max(0, Label_Y) for (const Line of Split_Lines_List) { const Box_Height = Line.length * 12 // Shadow Context.fillStyle = Color.SHADOW Context.fillRect(Label_X - Border_Pixel, Label_Y - Text_Size - Border_Pixel, Text_Width + Border_Pixel * 2 + Shadow_Pixel, Box_Height + Border_Pixel * 2 + Shadow_Pixel) // Context.fillStyle = 'rgba(220,220,0,1)' Context.fillStyle = Color.NOTE_BACKGROUND Context.fillRect(Label_X - Border_Pixel, Label_Y - Text_Size - Border_Pixel, Text_Width + Border_Pixel * 2 , Box_Height + Border_Pixel * 2) // Context.fillStyle = 'rgba(0,0,0)' Context.fillStyle = Color.GREEN for (const Label of Line) { Context.fillText(Label, Label_X, Label_Y) Label_Y += Text_Size + 1 } Label_Y += 16 } } }, resize:function() { const Width = Canvas.clientWidth const Height = Canvas.clientHeight Canvas.width = Width Canvas.height = Height // Inform the system so it can map coords for us Particle_System.screenSize(Width, Height) Renderer_Object.redraw() }, // https://stackoverflow.com/questions/9489271/arbor-js-node-onclick initMouseHandling:function(){ const Mouse_State = new Mouse_State_Class() function Event_Get_Mouse_Point(Event) { const Position = $(Canvas).offset() return arbor.Point(Event.pageX - Position.left, Event.pageY - Position.top) } function Event_Get_Nearest_Node(Event) { const Point_Mouse = Event_Get_Mouse_Point(Event) const Nearest = Particle_System.nearest(Point_Mouse) return [Point_Mouse, Nearest] } function Nearest_Get_Selected(Nearest) { if (!Nearest || !Nearest.node) return null return (Nearest.distance < 50) ? Nearest : null } const Handler = { mousemove:function(Event) { if (Mouse_State.Is_Down()) return false const [Point_Mouse, Nearest] = Event_Get_Nearest_Node(Event) if (!Nearest || !Nearest.node) return false const Selected = Nearest_Get_Selected(Nearest) if (Selected && Selected.node.data.link) { Dom.addClass('linkable') } else { Dom.removeClass('linkable') } const Nearest_Edge = Particle_System.Dings_Navigator.Get_Nearest_Edge(Point_Mouse, Nearest.node) if (Particle_System.Dings_Navigator.Select_Mode.value != Mode.REMOVE_EDGE) Particle_System.Dings_Navigator.Switch_Center_Node(Nearest.node.name) if (Nearest_Edge) Particle_System.Dings_Navigator.Switch_Center_Edge(Nearest_Edge) return false }, clicked:function(Event) { const [Point_Mouse, Nearest] = Event_Get_Nearest_Node(Event) const Nearest_Edge = Particle_System.Dings_Navigator.Get_Nearest_Edge(Point_Mouse) if (Particle_System.Dings_Navigator.Select_Mode.value == Mode.REMOVE_EDGE) { if (Nearest_Edge) { Particle_System.Dings_Navigator.History_Before_State_Change() Particle_System.pruneEdge(Nearest_Edge) Particle_System.Dings_Navigator.History_After_State_Change() } return false } if (!Nearest || !Nearest.node) return false const Selected = Nearest_Get_Selected(Nearest) if (!Selected) return false if (Particle_System.Dings_Navigator.Process_Locked(Selected.node) == true) return false console.log("Click Node") if (Nearest.node === Selected.node) { Particle_System.Dings_Navigator.Switch_to_Node(Selected.node.name) return false } return false }, mousedown:function(Event) { const [Point_Mouse, Nearest] = Event_Get_Nearest_Node(Event) Mouse_State.Set_Down(Nearest) if (Mouse_State.Dragged_Node && Mouse_State.Dragged_Node.node) Mouse_State.Dragged_Node.node.fixed = true $(Canvas).bind('mousemove', Handler.dragged) $(window).bind('mouseup', Handler.dropped) return false }, dragged:function(Event) { const Screen_Point = Event_Get_Mouse_Point(Event) Mouse_State.Set_Dragging() if (!Mouse_State.Dragged_Node || !Mouse_State.Dragged_Node.node) return false const Point = Particle_System.fromScreen(Screen_Point) Mouse_State.Dragged_Node.node.p = Point return false }, dropped:function(Event) { const Dragged_Node = Mouse_State.Dragged_Node $(Canvas).unbind('mousemove', Handler.dragged) $(window).unbind('mouseup', Handler.dropped) const Mouse_Was_Clicked = Mouse_State.Is_Click() Mouse_State.Set_Idle() if (!Dragged_Node || !Dragged_Node.node) return false Dragged_Node.node.fixed = false Dragged_Node.node.tempMass = 50 if (Mouse_Was_Clicked) Handler.clicked(Event) return false } } $(Canvas).mousedown(Handler.mousedown) $(Canvas).mousemove(Handler.mousemove) }, } return Renderer_Object } // Main console.log("Flex") this.Flex_Index_Local = FlexSearch.Index({tokenize: "full"}) this.Flex_Index_Global = FlexSearch.Index({tokenize: "full"}) this.Flex_Index_Global_Mapping = {} this.Flex_Index_Numbers = FlexSearch.Index({tokenize: "full"}) this.Html_Id = Html_Id // Dings-Number-Input this.Dings_Number_Input = document.getElementById(Html_Id + "." + "Dings_Number_Input") this.Dings_Number_Input.addEventListener("keyup", this.Number_Input_Handle_Key_Up) this.Dings_Number_Input.addEventListener("change", this.Number_Input_Handle_Search) this.Dings_Number_Data_List = document.getElementById(Html_Id + "." + "Dings_Number_Data_List") this.Dings_Number_Data_List_View = new Data_List_Class(this.Dings_Number_Data_List) // Dings-Name-Input this.Dings_Name_Input = document.getElementById(Html_Id + "." + "Dings_Name_Input") this.Dings_Name_Input.addEventListener("keyup", this.Name_Input_Handle_Key_Up) this.Dings_Name_Input.addEventListener("search", this.Name_Input_Handle_Search) this.Dings_Name_Input.addEventListener("change", this.Name_Input_Handle_Search) this.Dings_Name_Data_List = document.getElementById(Html_Id + "." + "Dings_Name_Data_List") this.Dings_Name_Data_List_View = new Name_Data_List_Class(this.Dings_Name_Data_List, this.Flex_Index_Global_Mapping) // Dings-Type-Number-Input this.Dings_Type_Number_Input = document.getElementById(Html_Id + "." + "Dings_Type_Number_Input") this.Dings_Type_Number_Input.addEventListener("keyup", this.Type_Number_Input_Handle_Key_Up) this.Dings_Type_Number_Input.addEventListener("search", this.Type_Number_Input_Handle_Search) this.Dings_Type_Number_Input.addEventListener("change", this.Type_Number_Input_Handle_Search) this.Dings_Type_Number_Data_List = document.getElementById(Html_Id + "." + "Dings_Type_Number_Data_List") this.Dings_Type_Number_Data_List_View = new Data_List_Class(this.Dings_Type_Number_Data_List) // Dings-Type-Name-Input this.Dings_Type_Name_Input = document.getElementById(Html_Id + "." + "Dings_Type_Name_Input") this.Dings_Type_Name_Input.addEventListener("keyup", this.Type_Name_Input_Handle_Key_Up) this.Dings_Type_Name_Input.addEventListener("search", this.Type_Name_Input_Handle_Search) this.Dings_Type_Name_Input.addEventListener("change", this.Type_Name_Input_Handle_Search) this.Dings_Type_Name_Data_List = document.getElementById(Html_Id + "." + "Dings_Type_Name_Data_List") this.Dings_Type_Name_Data_List_View = new Name_Data_List_Class(this.Dings_Type_Name_Data_List, this.Flex_Index_Global_Mapping) // Mode this.Select_Mode = document.getElementById(Html_Id + "." + "Dings_Select_Mode") this.Select_Mode.addEventListener("change", this.Select_Mode_Handle_Change) // Scope this.Select_Scope = document.getElementById(Html_Id + "." + "Dings_Select_Scope") this.Select_Scope.addEventListener("change", this.Select_Scope_Handle_Change) this.Dings_Definition = document.getElementById(Html_Id + "." + "Dings_Definition") this.Dings_Statements = document.getElementById(Html_Id + "." + "Dings_Statements") this.Json_Download = document.getElementById(Html_Id + "." + "Json_Download") this.Json_Download.addEventListener('click', this.Download_Json_Handler) this.Image_Map_Download = document.getElementById(Html_Id + "." + "Image_Map_Download") this.Image_Map_Download.addEventListener('click', this.Download_Image_Map_Handler) this.History_Backward_Button = document.getElementById(Html_Id + "." + "History_Backward") this.History_Forward_Button = document.getElementById(Html_Id + "." + "History_Forward") this.History_Register_Buttons(this.History_Backward_Button, this.History_Forward_Button) this.History_Backward_Button.addEventListener('click', (function() { this.History_Backward() }).bind(this)) this.History_Forward_Button.addEventListener('click', (function() { this.History_Forward() }).bind(this)) this.Switch_Center_Node_Locked = false this.Node_Last_Clicked = false this.Renderer = Renderer("#" + Html_Id + "." + "viewport") this.Init_Particle_System() this.Node_Center = false this.Focus_Dings_Number = false this.Node_Map = {} this.Node_Count_Max = 100 this.Node_Count = 0 this.Edge_Center = undefined this.Target_Node_List = [] const Test_Data_Dict = { Value1: "Hello-Jay", Value2: "Blanks-are-not-working-here" } Dings_Lib.Api_Call_Async("list -a", Test_Data_Dict).then(Result => { console.log("Result: " + Result) this.Dings_Json = JSON.parse(Result) let Mapping_Index = 0 let Json for (const [Dings_Number, Dings] of Object.entries(this.Dings_Json.Dings_List)) { this.Flex_Index_Global_Mapping[Mapping_Index] = [Dings_Number, Dings.Name] this.Flex_Index_Global.add(Mapping_Index, Dings.Name) this.Flex_Index_Numbers.add(Dings_Number, Dings_Number) Mapping_Index++ for (const Alias of Dings.Aliases) { this.Flex_Index_Global_Mapping[Mapping_Index] = [Dings_Number, Alias] this.Flex_Index_Global.add(Mapping_Index, Alias) Mapping_Index++ } } const Dict = Dings_Lib.Dict_From_Url(this.Html_Id) if ("Center_Node" in Dict) { console.log("Load from Url") Json = Dict } else { console.log("Load from Dings-Json") Json = Dings_Json } this.Load_Json(Json) this.History_Set_Initial_State() }) } }