IEnumerable <SENode> TraverseParents(GraphNode focusNode, SENode seFocusNode, String traversalFilter, Int32 depth) { const String fcn = "TraverseParents"; Regex traversalFilterRex = new Regex(traversalFilter); HashSet <GraphNode> parentNodes = new HashSet <GraphNode>(); parentNodes.Add(focusNode); foreach (GraphNode.Link parentLink in focusNode.ParentLinks) { if ( (depth >= 0) && (traversalFilterRex.IsMatch(parentLink.Traversal.TraversalName)) && (parentNodes.Contains(parentLink.Node) == false) ) { var parentNode = parentLink.Node; // we want to link to top level parent, not element node. while ((parentNode != null) && (parentNode.Anchor.Item != null)) { switch (parentNode.ParentLinks.Count) { case 0: this.ParseItemError(parentNode.TraceMsg(), fcn, $"No parent nodes found"); parentNode = null; break; case 1: parentNode = parentNode.ParentLinks[0].Node; break; default: this.ParseItemError(parentNode.TraceMsg(), fcn, $"Multiple ({parentNode.ParentLinks.Count}) parent nodes detected"); break; } } if (parentNode != null) { SENode parent = CreateNode(parentNode); yield return(parent); } } } }
void RenderLegend(IEnumerable <GraphLegend> legend, HashSet <String> cssClasses, float x, float y) { SvgGroup legendGroup = this.doc.AddGroup(null); foreach (GraphLegend legendItem in legend) { bool CssClassUsed() => cssClasses.Contains(legendItem.CssClass); void RenderLegendItem() { SENode node = new SENode { Class = legendItem.CssClass }; node.AddTextLine(legendItem.Item); Render(legendGroup, node, x, y, null, out float width, out float height); x = x + width + this.NodeGapX; float bottom = y + height; if (this.maxX < x) { this.maxX = x; } if (this.maxY < bottom) { this.maxY = bottom; } } if (CssClassUsed()) { RenderLegendItem(); } } }
public void RenderFocusGraph(String cssFile, GraphNode focusGraphNode, Int32 depth, String traversalName, String graphName, HashSet <String> keys = null) { SvgEditor e = new SvgEditor(graphName); e.AddCssFile(cssFile); lock (this.svgEditors) { this.svgEditors.Add(e); } SENodeGroup seGroupParents = new SENodeGroup("", "parents"); SENodeGroup seGroupFocus = new SENodeGroup("", "focus"); SENodeGroup seGroupChildren = new SENodeGroup("", "children"); seGroupParents.AppendGroup(seGroupFocus); seGroupFocus.AppendGroup(seGroupChildren); SENode focusSENode = this.CreateNode(focusGraphNode); focusSENode.Class = "focus"; seGroupFocus.AppendNode(focusSENode); { IEnumerable <SENode> parentNodes = TraverseParents(focusGraphNode, focusSENode, $"{traversalName}/*", 1); seGroupParents.AppendNodeRange(parentNodes); } { IEnumerable <SENodeGroup> childNodes = TraverseChildren(focusGraphNode, $"{traversalName}/*", depth, keys, new Stack <GraphNode>()); seGroupFocus.AppendGroupRange(childNodes); } seGroupParents.Sort(); this.legends.TryGetValue("focus", out List <GraphLegend> legendNodes); e.Render(seGroupParents, legendNodes); }
protected SENode CreateNodeBinding(ElementDefinition.ElementDefinitionBindingComponent binding) { String hRef = null; SENode node = new SENode() { HRef = hRef }; node.Class = "valueSet"; String displayName = binding.ValueSet.LastPathPart(); if (this.TryGetValueSet(binding.ValueSet, out ValueSet vs) == false) { displayName = vs.Name; } node.AddTextLine(displayName, hRef); node.LhsAnnotation = "bind"; return(node); }
IEnumerable <SENodeGroup> TraverseChildren(GraphNode focusNode, String traversalFilter, Int32 depth, HashSet <String> keys, Stack <GraphNode> nodeStack) { if (nodeStack.Contains(focusNode)) { throw new Exception($"Circular linkage at {focusNode.TraceMsg()}"); } nodeStack.Push(focusNode); Regex traversalFilterRex = new Regex(traversalFilter); bool HasKey(GraphNode.Link childLink) => (keys == null) || keys.Overlaps(childLink.Keys); foreach (GraphNode.Link childLink in focusNode.ChildLinks) { if ( (depth > 0) && (traversalFilterRex.IsMatch(childLink.Traversal.TraversalName)) && (HasKey(childLink)) ) { SENode child = CreateNode(childLink.Node); SENodeGroup childContainer = new SENodeGroup(child.SortPrefix, child.AllText()); childContainer.AppendNode(child); childContainer.AppendGroupRange(TraverseChildren(childLink.Node, traversalFilter, depth - childLink.Depth, keys, nodeStack)); yield return(childContainer); } } nodeStack.Pop(); }
protected SENode CreateNode(GraphNode graphNode) { SENode node = new SENode { HRef = graphNode.HRef }; node.Class = graphNode.CssClass; String displayName = graphNode.DisplayName; //Debug.Assert(displayName != "Breast/Radiology/Composition"); foreach (String titlePart in displayName.Split('/')) { String s = titlePart.Trim(); node.AddTextLine(s, graphNode.HRef); } node.SortPrefix = graphNode.SortPrefix; node.LhsAnnotation = ResolveAnnotation(graphNode, graphNode.LhsAnnotationText); node.RhsAnnotation = ResolveAnnotation(graphNode, graphNode.RhsAnnotationText); return(node); }
public void AppendNode(SENode node) { this.Nodes.Add(node); }
void Render(SvgGroup parentGroup, SENode node, float screenX, float screenY, HashSet <String> cssClasses, out float width, out float height) { void AddClass(String cssClassx) { if (cssClasses == null) { return; } if (cssClasses.Contains(cssClassx) == false) { cssClasses.Add(cssClassx); } } //Debug.Assert((this.RenderTestPoint == null) || node.AllText().Contains(RenderTestPoint) == false); height = node.TextLines.Count * this.LineHeight + 2 * this.BorderMargin; width = node.Width / 15 + 2 * this.BorderMargin; AddClass(parentGroup.Class); SvgGroup g = this.doc.AddGroup(parentGroup); g.Class = parentGroup.Class; g.Transform = $"translate({this.ToPx(screenX)} {this.ToPx(screenY)})"; SvgRect square; if (node.HRef != null) { SvgHyperLink l = this.doc.AddHyperLink(g); l.Target = "_top"; l.HRef = node.HRef.ToString(); square = this.doc.AddRect(l); } else { square = this.doc.AddRect(g); } AddClass(node.Class); square.Class = node.Class; square.RX = this.ToPx(this.RectRx); square.RY = this.ToPx(this.RectRy); square.X = "0"; square.Y = "0"; square.Width = this.ToPx(width); square.Height = this.ToPx(height); float textY = this.BorderMargin + 1; foreach (SEText line in node.TextLines) { SvgText t; if (line.HRef != null) { SvgHyperLink l = this.doc.AddHyperLink(g); l.HRef = line.HRef; l.Target = "_top"; if (line.Title != null) { SvgTitle title = this.doc.AddTitle(l); title.Value = line.Title; } t = this.doc.AddText(l); } else { t = this.doc.AddText(g); } t.Class = GetClass(line.Class, node.Class); AddClass(t.Class); t.X = this.ToPx(this.BorderMargin + this.BorderWidth); t.Y = this.ToPx(textY); t.TextAnchor = "left"; t.Value = line.Text; textY += this.LineHeight; } }