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 = ``
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()
})
}
}