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 mentity
= mentity_from_uri
(req
, res
)
35 if mentity
== null then return
36 var pdepth
= req
.int_arg
("pdepth")
37 var cdepth
= req
.int_arg
("cdepth")
38 var g
= new InheritanceGraph(mentity
, config
.view
)
39 res
.send g
.draw
(pdepth
, cdepth
).to_svg
43 # Graph for mentity hierarchies
45 # Recursively build parents and children list from a `center`.
46 class InheritanceGraph
49 # MEntity at the center of this graph
52 # ModelView used to filter graph
56 var graph
: DotGraph is lazy
do
57 var graph
= new DotGraph("package_diagram", "digraph")
59 graph
["compound"] = "true"
60 graph
["rankdir"] = "BT"
61 graph
["ranksep"] = 0.3
62 graph
["nodesep"] = 0.3
64 graph
.nodes_attrs
["margin"] = 0.1
65 graph
.nodes_attrs
["width"] = 0
66 graph
.nodes_attrs
["height"] = 0
67 graph
.nodes_attrs
["fontsize"] = 10
68 graph
.nodes_attrs
["fontname"] = "helvetica"
70 graph
.edges_attrs
["dir"] = "none"
71 graph
.edges_attrs
["color"] = "gray"
77 fun draw
(parents_depth
, children_depth
: nullable Int): DotGraph do
79 draw_parents
(center
, parents_depth
)
80 draw_children
(center
, children_depth
)
84 private var nodes
= new HashMap[MEntity, DotElement]
85 private var done_parents
= new HashSet[MEntity]
86 private var done_children
= new HashSet[MEntity]
88 # Recursively draw parents of mentity
89 fun draw_parents
(mentity
: MEntity, max_depth
: nullable Int, current_depth
: nullable Int) do
90 if done_parents
.has
(mentity
) then return
91 done_parents
.add mentity
92 current_depth
= current_depth
or else 0
93 if max_depth
!= null and current_depth
>= max_depth
then
94 from_dotdotdot
(mentity
)
97 var parents
= mentity
.collect_parents
(view
)
98 if parents
.length
> 10 then
99 from_dotdotdot
(mentity
)
102 for parent
in parents
do
103 if parent
isa MModule then
104 var mgroup
= parent
.mgroup
105 if mgroup
!= null and mgroup
.default_mmodule
== parent
then parent
= mgroup
107 if parent
isa MGroup then
108 if parent
.mpackage
.mgroups
.first
== parent
then parent
= parent
.mpackage
110 draw_edge
(mentity
, parent
)
112 for parent
in parents
do
113 if parent
isa MModule then
114 var mgroup
= parent
.mgroup
115 if mgroup
!= null and mgroup
.default_mmodule
== parent
then parent
= mgroup
117 if parent
isa MGroup then
118 if parent
.mpackage
.mgroups
.first
== parent
then parent
= parent
.mpackage
120 draw_parents
(parent
, max_depth
, current_depth
+ 1)
124 # Recursively draw children of mentity
125 fun draw_children
(mentity
: MEntity, max_depth
: nullable Int, current_depth
: nullable Int) do
126 if done_children
.has
(mentity
) then return
127 done_children
.add mentity
128 current_depth
= current_depth
or else 0
129 if max_depth
!= null and current_depth
>= max_depth
then
130 to_dotdotdot
(mentity
)
133 var children
= mentity
.collect_children
(view
)
134 if children
.length
> 10 then
135 to_dotdotdot
(mentity
)
138 for child
in children
do
139 if child
isa MGroup then
140 if child
.mpackage
.mgroups
.first
== child
then child
= child
.mpackage
142 draw_edge
(child
, mentity
)
144 for child
in children
do
145 if child
isa MGroup then
146 if child
.mpackage
.mgroups
.first
== child
then child
= child
.mpackage
148 draw_children
(child
, max_depth
, current_depth
+ 1)
152 # Draw a node from a `mentity`
153 fun draw_node
(mentity
: MEntity): DotElement do
154 if nodes
.has_key
(mentity
) then return nodes
[mentity
]
155 var node
: DotElement = mentity
.to_dot_node
156 if mentity
== center
then node
= highlight
(node
)
157 nodes
[mentity
] = node
162 private var edges
= new HashMap2[MEntity, MEntity, DotEdge]
164 # Draw a edges between two mentities
165 fun draw_edge
(from
, to
: MEntity): DotEdge do
166 if edges
.has
(from
, to
) then return edges
[from
, to
].as(not null)
167 if edges
.has
(to
, from
) then return edges
[to
, from
].as(not null)
168 var nfrom
= draw_node
(from
)
169 var nto
= draw_node
(to
)
170 var edge
= new DotEdge(nfrom
, nto
)
171 edges
[from
, to
] = edge
176 private var to_dots
= new HashMap[MEntity, DotElement]
178 # Create a link from `mentity` to a `...` node
179 fun to_dotdotdot
(mentity
: MEntity): DotEdge do
180 var nto
= draw_node
(mentity
)
181 var dots
= to_dots
.get_or_null
(mentity
)
183 dots
= dotdotdot
("{nto.id}...")
184 to_dots
[mentity
] = dots
187 var edge
= new DotEdge(dots
, nto
)
192 private var from_dots
= new HashMap[MEntity, DotElement]
194 # Create a link from a `...` node to a `mentity`
195 fun from_dotdotdot
(mentity
: MEntity): DotEdge do
196 var nfrom
= draw_node
(mentity
)
197 var dots
= to_dots
.get_or_null
(mentity
)
199 dots
= dotdotdot
("...{nfrom.id}")
200 from_dots
[mentity
] = dots
203 var edge
= new DotEdge(dots
, nfrom
)
208 # Change the border color of the node
209 fun highlight
(dot
: DotElement): DotElement do
210 dot
["color"] = "#1E9431"
214 # Generate a `...` node
215 fun dotdotdot
(id
: String): DotNode do
216 var node
= new DotNode(id
)
217 node
["label"] = "..."
218 node
["shape"] = "none"
224 private fun to_dot_node
: DotNode do
225 var node
= new DotNode(full_name
)
226 node
["URL"] = web_url
233 redef fun to_dot_node
do
235 node
["shape"] = "tab"
241 redef fun to_dot_node
do
243 node
["shape"] = "folder"
249 redef fun to_dot_node
do
251 node
["shape"] = "note"
257 redef fun to_dot_node
do
259 node
["shape"] = "box"