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.
22 # Group all api handlers in one router.
26 # Model to pass to handlers.
29 # Mainmodule to pass to handlers.
30 var mainmodule
: MModule
33 use
("/inheritance/:id", new APIInheritanceGraph(model
, mainmodule
))
37 # Render a hierarchy graph for `mentity` if any.
38 class APIInheritanceGraph
41 redef fun get
(req
, res
) do
42 var pdepth
= req
.int_arg
("pdepth")
43 var cdepth
= req
.int_arg
("cdepth")
44 var mentity
= mentity_from_uri
(req
, res
)
45 if mentity
== null then
49 var g
= new InheritanceGraph(mentity
, view
)
50 res
.send g
.draw
(pdepth
, cdepth
).to_svg
54 # Graph for mentity hierarchies
56 # Recursively build parents and children list from a `center`.
57 class InheritanceGraph
60 # MEntity at the center of this graph
63 # ModelView used to filter graph
67 var graph
: DotGraph is lazy
do
68 var graph
= new DotGraph("package_diagram", "digraph")
70 graph
["compound"] = "true"
71 graph
["rankdir"] = "BT"
72 graph
["ranksep"] = 0.3
73 graph
["nodesep"] = 0.3
75 graph
.nodes_attrs
["margin"] = 0.1
76 graph
.nodes_attrs
["width"] = 0
77 graph
.nodes_attrs
["height"] = 0
78 graph
.nodes_attrs
["fontsize"] = 10
79 graph
.nodes_attrs
["fontname"] = "helvetica"
81 graph
.edges_attrs
["dir"] = "none"
82 graph
.edges_attrs
["color"] = "gray"
88 fun draw
(parents_depth
, children_depth
: nullable Int): DotGraph do
90 draw_parents
(center
, parents_depth
)
91 draw_children
(center
, children_depth
)
95 private var nodes
= new HashMap[MEntity, DotElement]
96 private var done_parents
= new HashSet[MEntity]
97 private var done_children
= new HashSet[MEntity]
99 # Recursively draw parents of mentity
100 fun draw_parents
(mentity
: MEntity, max_depth
: nullable Int, current_depth
: nullable Int) do
101 if done_parents
.has
(mentity
) then return
102 done_parents
.add mentity
103 current_depth
= current_depth
or else 0
104 if max_depth
!= null and current_depth
>= max_depth
then
105 from_dotdotdot
(mentity
)
108 var parents
= mentity
.collect_parents
(view
)
109 if parents
.length
> 10 then
110 from_dotdotdot
(mentity
)
113 for parent
in parents
do
114 if parent
isa MModule then
115 var mgroup
= parent
.mgroup
116 if mgroup
!= null and mgroup
.default_mmodule
== parent
then parent
= mgroup
118 if parent
isa MGroup then
119 if parent
.mpackage
.mgroups
.first
== parent
then parent
= parent
.mpackage
121 draw_edge
(mentity
, parent
)
123 for parent
in parents
do
124 if parent
isa MModule then
125 var mgroup
= parent
.mgroup
126 if mgroup
!= null and mgroup
.default_mmodule
== parent
then parent
= mgroup
128 if parent
isa MGroup then
129 if parent
.mpackage
.mgroups
.first
== parent
then parent
= parent
.mpackage
131 draw_parents
(parent
, max_depth
, current_depth
+ 1)
135 # Recursively draw children of mentity
136 fun draw_children
(mentity
: MEntity, max_depth
: nullable Int, current_depth
: nullable Int) do
137 if done_children
.has
(mentity
) then return
138 done_children
.add mentity
139 current_depth
= current_depth
or else 0
140 if max_depth
!= null and current_depth
>= max_depth
then
141 to_dotdotdot
(mentity
)
144 var children
= mentity
.collect_children
(view
)
145 if children
.length
> 10 then
146 to_dotdotdot
(mentity
)
149 for child
in children
do
150 if child
isa MGroup then
151 if child
.mpackage
.mgroups
.first
== child
then child
= child
.mpackage
153 draw_edge
(child
, mentity
)
155 for child
in children
do
156 if child
isa MGroup then
157 if child
.mpackage
.mgroups
.first
== child
then child
= child
.mpackage
159 draw_children
(child
, max_depth
, current_depth
+ 1)
163 # Draw a node from a `mentity`
164 fun draw_node
(mentity
: MEntity): DotElement do
165 if nodes
.has_key
(mentity
) then return nodes
[mentity
]
166 var node
: DotElement = mentity
.to_dot_node
167 if mentity
== center
then node
= highlight
(node
)
168 nodes
[mentity
] = node
173 private var edges
= new HashMap2[MEntity, MEntity, DotEdge]
175 # Draw a edges between two mentities
176 fun draw_edge
(from
, to
: MEntity): DotEdge do
177 if edges
.has
(from
, to
) then return edges
[from
, to
].as(not null)
178 if edges
.has
(to
, from
) then return edges
[to
, from
].as(not null)
179 var nfrom
= draw_node
(from
)
180 var nto
= draw_node
(to
)
181 var edge
= new DotEdge(nfrom
, nto
)
182 edges
[from
, to
] = edge
187 private var to_dots
= new HashMap[MEntity, DotElement]
189 # Create a link from `mentity` to a `...` node
190 fun to_dotdotdot
(mentity
: MEntity): DotEdge do
191 var nto
= draw_node
(mentity
)
192 var dots
= to_dots
.get_or_null
(mentity
)
194 dots
= dotdotdot
("{nto.id}...")
195 to_dots
[mentity
] = dots
198 var edge
= new DotEdge(dots
, nto
)
203 private var from_dots
= new HashMap[MEntity, DotElement]
205 # Create a link from a `...` node to a `mentity`
206 fun from_dotdotdot
(mentity
: MEntity): DotEdge do
207 var nfrom
= draw_node
(mentity
)
208 var dots
= to_dots
.get_or_null
(mentity
)
210 dots
= dotdotdot
("...{nfrom.id}")
211 from_dots
[mentity
] = dots
214 var edge
= new DotEdge(dots
, nfrom
)
219 # Change the border color of the node
220 fun highlight
(dot
: DotElement): DotElement do
221 dot
["color"] = "#1E9431"
225 # Generate a `...` node
226 fun dotdotdot
(id
: String): DotNode do
227 var node
= new DotNode(id
)
228 node
["label"] = "..."
229 node
["shape"] = "none"
235 private fun to_dot_node
: DotNode do
236 var node
= new DotNode(full_name
)
237 node
["URL"] = web_url
244 redef fun to_dot_node
do
246 node
["shape"] = "tab"
252 redef fun to_dot_node
do
254 node
["shape"] = "folder"
260 redef fun to_dot_node
do
262 node
["shape"] = "note"
268 redef fun to_dot_node
do
270 node
["shape"] = "box"