Open ghost opened 4 years ago
I think the bug is that SvgGraphWriter does not output the boxes and labels of subgraphs.
Mostly that's easy to do in WriteNodes I think, keeping in mind placing the label can be trickier, I used the following algorithm to place label at top of a subgraph box, which ill openly admit to being a hack!
// e.g. graph.RootSubgraph.AllSubgraphsDepthFirstExcludingSelf() |> Seq.iter (writeNode true)
if isSubgraph then
let n = Node(node.Label.Text)
n.Attr.Color <- node.Attr.Color
n.Attr.FillColor <- Color.White // make clean for text
// take the subgraph box
// take the subgraph label
// write a new box ontop of subgraph box containing label
let l = node.Label
// guess box size for label based on text length
// scale is a bit of a hack @ 1.5
// TODO: StringMeasure.MeasureWithFont might be better here
let h = l.FontSize + 4.0 // ensure box is slightly bigger
let w = ((l.FontSize * float l.Text.Length) * 1.5) / 2.0
let boundingBox = node.GeometryNode.BoundingBox
let topCenter = boundingBox.Left + boundingBox.Width/2.0
let x = topCenter - (w/2.0)
let y = boundingBox.Top + (h/2.0) // intersect
// y-coordinates must be inverted to fir in svg space
// normally done by geo transform but we are manually calculating label rect
writeBox2 n.Attr x -y w h
// we also want to make sure we dont right over top of box line
// so y must be adjusted to fit
let labelY = -(y-(h/2.0))
let labelX = x + (w/2.0) // we dont want to write directly at box start
writeLabel xml node.Label (Some(labelX, labelY))
This works well when the graph is laid out with default Sugiyama, however when using Layout.Layered.LayeredLayout, it seems to not respect the subgraphs bounds, and the layout ends up being very odd (subgraph box is nowhere near subgraph nodes, as the nodes are all spread out).
If you have any ideas on how to use a layered layout (similar to this), I would be grateful, I am struggling a bit with my very limited understanding of graph layout.
We can to reuse the code from GraphViewerGdi here, for example look for CreateDNodeAndSetNodeBoundaryCurveForSubgraph. Sorry, I have no time to implement it now.
I understand, thank you for your help :) I will dig into that section of the code!
After graph.CreateGeometryGraph(), each Node has populated geometry. When we write to SVG we use a transpose to flip y-coordinate (TransformGraphByFlippingY). This does not touch the geometry on the subgraph, making the node and edge geo not intersect with the subgraph box, this only becomes an issue when wanting to draw the subgraph (for example, as a box). There are two ways around this:
graph.GeometryGraph.Nodes.Add(actualSubgraph.GeometryNode)
I am not sure which is the correct way of doing it, but provided they both occur post-layout, it shouldn't affect things dramatically
I don't think this is a bug, but it took me a good couple hours so solve, so I wanted to document somewhere others could find it.