1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Render various graph from a model.
25 use
("/graph/inheritance/:id", new APIInheritanceGraph(config
))
29 # Render a hierarchy graph for `mentity` if any.
30 class APIInheritanceGraph
33 redef fun get
(req
, res
) do
34 var pdepth
= req
.int_arg
("pdepth")
35 var cdepth
= req
.int_arg
("cdepth")
36 var mentity
= mentity_from_uri
(req
, res
)
37 if mentity
== null then
41 var g
= new InheritanceGraph(mentity
, view
)
42 res
.send g
.draw
(pdepth
, cdepth
).to_svg
46 # Graph for mentity hierarchies
48 # Recursively build parents and children list from a `center`.
49 class InheritanceGraph
52 # MEntity at the center of this graph
55 # ModelView used to filter graph
59 var graph
: DotGraph is lazy
do
60 var graph
= new DotGraph("package_diagram", "digraph")
62 graph
["compound"] = "true"
63 graph
["rankdir"] = "BT"
64 graph
["ranksep"] = 0.3
65 graph
["nodesep"] = 0.3
67 graph
.nodes_attrs
["margin"] = 0.1
68 graph
.nodes_attrs
["width"] = 0
69 graph
.nodes_attrs
["height"] = 0
70 graph
.nodes_attrs
["fontsize"] = 10
71 graph
.nodes_attrs
["fontname"] = "helvetica"
73 graph
.edges_attrs
["dir"] = "none"
74 graph
.edges_attrs
["color"] = "gray"
80 fun draw
(parents_depth
, children_depth
: nullable Int): DotGraph do
82 draw_parents
(center
, parents_depth
)
83 draw_children
(center
, children_depth
)
87 private var nodes
= new HashMap[MEntity, DotElement]
88 private var done_parents
= new HashSet[MEntity]
89 private var done_children
= new HashSet[MEntity]
91 # Recursively draw parents of mentity
92 fun draw_parents
(mentity
: MEntity, max_depth
: nullable Int, current_depth
: nullable Int) do
93 if done_parents
.has
(mentity
) then return
94 done_parents
.add mentity
95 current_depth
= current_depth
or else 0
96 if max_depth
!= null and current_depth
>= max_depth
then
97 from_dotdotdot
(mentity
)
100 var parents
= mentity
.collect_parents
(view
)
101 if parents
.length
> 10 then
102 from_dotdotdot
(mentity
)
105 for parent
in parents
do
106 if parent
isa MModule then
107 var mgroup
= parent
.mgroup
108 if mgroup
!= null and mgroup
.default_mmodule
== parent
then parent
= mgroup
110 if parent
isa MGroup then
111 if parent
.mpackage
.mgroups
.first
== parent
then parent
= parent
.mpackage
113 draw_edge
(mentity
, parent
)
115 for parent
in parents
do
116 if parent
isa MModule then
117 var mgroup
= parent
.mgroup
118 if mgroup
!= null and mgroup
.default_mmodule
== parent
then parent
= mgroup
120 if parent
isa MGroup then
121 if parent
.mpackage
.mgroups
.first
== parent
then parent
= parent
.mpackage
123 draw_parents
(parent
, max_depth
, current_depth
+ 1)
127 # Recursively draw children of mentity
128 fun draw_children
(mentity
: MEntity, max_depth
: nullable Int, current_depth
: nullable Int) do
129 if done_children
.has
(mentity
) then return
130 done_children
.add mentity
131 current_depth
= current_depth
or else 0
132 if max_depth
!= null and current_depth
>= max_depth
then
133 to_dotdotdot
(mentity
)
136 var children
= mentity
.collect_children
(view
)
137 if children
.length
> 10 then
138 to_dotdotdot
(mentity
)
141 for child
in children
do
142 if child
isa MGroup then
143 if child
.mpackage
.mgroups
.first
== child
then child
= child
.mpackage
145 draw_edge
(child
, mentity
)
147 for child
in children
do
148 if child
isa MGroup then
149 if child
.mpackage
.mgroups
.first
== child
then child
= child
.mpackage
151 draw_children
(child
, max_depth
, current_depth
+ 1)
155 # Draw a node from a `mentity`
156 fun draw_node
(mentity
: MEntity): DotElement do
157 if nodes
.has_key
(mentity
) then return nodes
[mentity
]
158 var node
: DotElement = mentity
.to_dot_node
159 if mentity
== center
then node
= highlight
(node
)
160 nodes
[mentity
] = node
165 private var edges
= new HashMap2[MEntity, MEntity, DotEdge]
167 # Draw a edges between two mentities
168 fun draw_edge
(from
, to
: MEntity): DotEdge do
169 if edges
.has
(from
, to
) then return edges
[from
, to
].as(not null)
170 if edges
.has
(to
, from
) then return edges
[to
, from
].as(not null)
171 var nfrom
= draw_node
(from
)
172 var nto
= draw_node
(to
)
173 var edge
= new DotEdge(nfrom
, nto
)
174 edges
[from
, to
] = edge
179 private var to_dots
= new HashMap[MEntity, DotElement]
181 # Create a link from `mentity` to a `...` node
182 fun to_dotdotdot
(mentity
: MEntity): DotEdge do
183 var nto
= draw_node
(mentity
)
184 var dots
= to_dots
.get_or_null
(mentity
)
186 dots
= dotdotdot
("{nto.id}...")
187 to_dots
[mentity
] = dots
190 var edge
= new DotEdge(dots
, nto
)
195 private var from_dots
= new HashMap[MEntity, DotElement]
197 # Create a link from a `...` node to a `mentity`
198 fun from_dotdotdot
(mentity
: MEntity): DotEdge do
199 var nfrom
= draw_node
(mentity
)
200 var dots
= to_dots
.get_or_null
(mentity
)
202 dots
= dotdotdot
("...{nfrom.id}")
203 from_dots
[mentity
] = dots
206 var edge
= new DotEdge(dots
, nfrom
)
211 # Change the border color of the node
212 fun highlight
(dot
: DotElement): DotElement do
213 dot
["color"] = "#1E9431"
217 # Generate a `...` node
218 fun dotdotdot
(id
: String): DotNode do
219 var node
= new DotNode(id
)
220 node
["label"] = "..."
221 node
["shape"] = "none"
227 private fun to_dot_node
: DotNode do
228 var node
= new DotNode(full_name
)
229 node
["URL"] = web_url
236 redef fun to_dot_node
do
238 node
["shape"] = "tab"
244 redef fun to_dot_node
do
246 node
["shape"] = "folder"
252 redef fun to_dot_node
do
254 node
["shape"] = "note"
260 redef fun to_dot_node
do
262 node
["shape"] = "box"