/// <summary> /// Callback that actually creates the node and its business object /// </summary> private INode CreateNodeCallback(IInputModeContext context, IGraph graph, PointD location, INode parent) { RectD newBounds = RectD.FromCenter(location, graph.NodeDefaults.Size); var node = graph.CreateNode(newBounds, graph.NodeDefaults.GetStyleInstance(), new MyBusinessObject(0.3)); return(node); }
/// <summary> /// Aggregates the nodes to a new aggregation node. /// </summary> /// <remarks> /// Adds a label with the number of aggregated nodes and adds labels /// to all created aggregation edges with the number of replaced original edges. /// </remarks> private void Aggregate <TKey>(IList <INode> nodes, TKey key, Func <TKey, INodeStyle> styleFactory) { var size = Graph.NodeDefaults.Size * (1 + nodes.Count * 0.2); var layout = RectD.FromCenter(PointD.Origin, size); AggregateGraph.Aggregate(new ListEnumerable <INode>(nodes), layout, styleFactory(key)); }
/// <summary> /// Creates a GraphBuilder instance that's preconfigured with our demo's styles. /// </summary> internal static (GraphBuilder, NodesSource <INeo4jNode>, EdgesSource <IRelationship>) CreateGraphBuilder(GraphControl graphControl, IGraph graph, List <INeo4jNode> nodes, List <IRelationship> edges) { var builder = new GraphBuilder(graph); var nodesSource = builder.CreateNodesSource(nodes, n => n.Id); nodesSource.NodeCreator.TagProvider = n => n; var nodeStyle = new Neo4JNodeStyle(); nodesSource.NodeCreator.Defaults.Style = nodeStyle; nodesSource.NodeCreator.Defaults.Size = new SizeD(240, 80); var edgesSource = builder.CreateEdgesSource(edges, e => e.StartNodeId, e => e.EndNodeId, e => e.Id); edgesSource.EdgeCreator.Defaults.Style = new BezierEdgeStyle { TargetArrow = Arrows.Default }; var labelBinding = edgesSource.EdgeCreator.CreateLabelBinding(item => item.Type); labelBinding.Defaults.LayoutParameter = new EdgeSegmentLabelModel().CreateParameterFromSource(0, 0, EdgeSides.AboveEdge); builder.NodeCreated += (sender, e) => { // Ensure that nodes have the correct size e.Graph.SetNodeLayout(e.Item, RectD.FromCenter(e.Item.Layout.GetCenter(), nodeStyle.GetPreferredSize(e.Item))); }; return(builder, nodesSource, edgesSource); }
private VisualGroup CreateVisual(CanvasControl canvas) { RectD rect = canvas.ContentRect; ContextConfigurator configurator = new ContextConfigurator(rect) { Margins = new InsetsD(0, 0, 0, 0) }; // scale down if necessary if (ActualHeight > 0 && ActualHeight > 0) { if (ActualHeight < rect.Height || ActualWidth < rect.Width) { configurator.Scale = Math.Min(ActualWidth / rect.Width, ActualHeight / rect.Height); } RectD bounds = RectD.FromCenter(rect.Center, new SizeD(ActualWidth, ActualHeight) * (1 / configurator.Scale)); configurator.WorldBounds = bounds; } IRenderContext vc = configurator.CreateRenderContext(canvas); Transform transform = configurator.CreateWorldToIntermediateTransform(); Visual visual = canvas.ExportContent(vc); return(new VisualGroup { Children = { visual }, Clip = Clip, Transform = transform }); }
/// <summary> /// Creates a node of the specified type. /// </summary> /// <remarks> /// The method will specify the ports that the node should have based on its type. /// </remarks> private void CreateNode(IGraph graph, PointD location, LogicGateType type, string label, SizeD?size = null) { RectD newBounds = RectD.FromCenter(location, graph.NodeDefaults.Size); INode node; if (type >= LogicGateType.Timer) { node = graph.CreateNode(RectD.FromCenter(location, (SizeD)size), new ShapeNodeStyle { Pen = new Pen(Brushes.Black, 2) }); } else { node = graph.CreateNode(newBounds, new LogicGateNodeStyle { GateType = type }); } graph.AddLabel(node, label, InteriorLabelModel.Center); var portDescriptors = PortDescriptor.CreatePortDescriptors(type); // use relative port locations var model = new FreeNodePortLocationModel(); // add ports for all descriptors using the descriptor as the tag of the port foreach (var descriptor in portDescriptors) { // use the descriptor's location as offset var portLocationModelParameter = model.CreateParameter(PointD.Origin, new PointD(descriptor.X, descriptor.Y)); graph.AddPort(node, portLocationModelParameter, tag: descriptor); } }
/// <summary> /// Aggregates the <paramref name="aggregate"/> as well as all its children recursively. /// </summary> /// <remarks> /// Can be used to apply the initial aggregation. If this is not the initial aggregation run, it will reuse existing /// aggregation nodes. /// </remarks> /// <param name="aggregate">The "root" aggregate.</param> /// <returns>The aggregation node representing the passed <paramref name="aggregate"/></returns> public INode AggregateRecursively(NodeAggregation.Aggregate aggregate) { if (aggregate.Children.Count == 0) { return(aggregate.Node); } PointD originalCenter; if (aggregateToNode.TryGetValue(aggregate, out var node)) { originalCenter = node.Layout.GetCenter(); var aggregationInfo = (AggregationNodeInfo)node.Tag; if (aggregationInfo.IsAggregated) { return(node); } else { AggregateGraph.Separate(node); } } else { originalCenter = PointD.Origin; } var nodesToAggregate = aggregate.Children.Select(AggregateRecursively).ToList(); if (aggregate.Node != null) { nodesToAggregate.Add(aggregate.Node); } var size = 30 + Math.Sqrt(aggregate.DescendantWeightSum) * 4; var layout = RectD.FromCenter(originalCenter, new SizeD(size, size)); var aggregationNode = AggregateGraph.Aggregate(new ListEnumerable <INode>(nodesToAggregate), layout, AggregationNodeStyle); aggregateToNode[aggregate] = aggregationNode; aggregationNode.Tag = new AggregationNodeInfo(aggregate, true); if (aggregate.Node != null) { placeholderMap[aggregate.Node] = aggregationNode; CopyLabels(aggregate.Node, aggregationNode); } else { var maxChild = GetMostImportantDescendant(aggregate); if (maxChild.Node != null && maxChild.Node.Labels.Any()) { AggregateGraph.AddLabel(aggregationNode, $"({maxChild.Node.Labels[0].Text}, …)", FreeNodeLabelModel.Instance.CreateDefaultParameter(), DescendantLabelStyle); } } return(aggregationNode); }
/// <summary> /// Callback used by <see cref="GraphEditorInputMode"/> to actually create a node upon a click. /// </summary> /// <remarks> /// This method creates a dummy business object and associated it with a newly created node. /// </remarks> private INode CreateNode(IInputModeContext context, IGraph graph, PointD location, INode parent) { Customer c = new Customer("Sample Customer", "Your Computer", new Random((int)DateTime.Now.TimeOfDay.TotalMilliseconds).Next(99999)); var simpleNode = new SimpleNode { Tag = c, Style = customerNodeStyle, Layout = new MutableRectangle(0, 0, 10, 10) }; var preferredSize = customerNodeStyle.GetPreferredSize(graphControl.CreateRenderContext(), simpleNode); return(graph.CreateNode(RectD.FromCenter(location, preferredSize), customerNodeStyle, c)); }
/// <summary> /// Callback that actually creates the node and its business object /// </summary> private INode CreateNodeCallback(IInputModeContext context, IGraph graph, PointD location, INode parent) { RectD newBounds = RectD.FromCenter(location, graph.NodeDefaults.Size); var node = graph.CreateNode(newBounds); node.Tag = new LayerConstraintsInfo { Value = rand.Next(0, 7), Constraints = rand.NextDouble() < 0.9 }; return(node); }
public IVisual CreateVisual(IRenderContext context) { rectangle = new MutableRectangle(RectD.FromCenter(Center, new SizeD(PageWidth + Margin, PageHeight + Margin))); var rectVisual = new RectangleVisual(rectangle) { Pen = new Pen(Color.Black, 1) { DashStyle = DashStyle.Dash } }; return(rectVisual); }
/// <summary> /// Callback that actually creates the node and its business object /// </summary> private INode CreateNodeCallback(IInputModeContext context, IGraph graph, PointD location, INode parent) { RectD newBounds = RectD.FromCenter(location, graph.NodeDefaults.Size); // create a new node var node = graph.CreateNode(newBounds); // set the node tag to a new random sequence constraints node.Tag = new SequenceConstraintsInfo { Value = rand.Next(0, 7), Constraints = rand.NextDouble() < 0.9 }; return(node); }
/// <summary> /// Constructs the yFiles graph from the database results. /// </summary> /// <param name="nodes">A list of nodes from the database.</param> /// <param name="edges">A list of edges from the database.</param> /// <param name="clearGraph">A value indicating whether the current graph should be replaced.</param> /// <param name="initialLocation">The initial location of newly-created nodes.</param> private async Task BuildGraphAsync(List <INeo4jNode> nodes, List <IRelationship> edges, bool clearGraph, PointD initialLocation) { if (graphBuilder == null || clearGraph) { Graph.Clear(); this.nodes = nodes; this.edges = edges; (graphBuilder, nodesSource, edgesSource) = CreateGraphBuilder(graphControl, Graph, nodes, edges); // Move new nodes back in z-order to make it look like they show up from underneath the neighboring node graphBuilder.NodeCreated += (sender, e) => graphControl.GraphModelManager.GetCanvasObject(e.Item).ToBack(); } else { // Add new data to existing data nodes = this.nodes.Concat(nodes).Distinct(IdEqualityComparer <INeo4jNode> .Instance).ToList(); edges = this.edges.Concat(edges).Distinct(IdEqualityComparer <IRelationship> .Instance).ToList(); this.nodes.Clear(); this.nodes.AddRange(nodes); this.edges.Clear(); this.edges.AddRange(edges); } nodesSource.NodeCreator.LayoutProvider = n => RectD.FromCenter(initialLocation, Graph.NodeDefaults.Size); // Update the graph and detect which nodes have been added var existingNodes = new HashSet <INode>(Graph.Nodes); var existingEdges = new HashSet <IEdge>(Graph.Edges); graphBuilder.UpdateGraph(); var newNodes = Graph.Nodes.Except(existingNodes).ToList(); var newEdges = Graph.Edges.Except(existingEdges).ToList(); foreach (var node in newNodes) { incrementalNodes.Add(node); } foreach (var edge in newEdges) { incrementalNodes.Add(edge.GetSourceNode()); incrementalNodes.Add(edge.GetTargetNode()); } loadingIndicator.Visibility = Visibility.Collapsed; // Layout the graph if there are new items if (newNodes.Count > 0 || newEdges.Count > 0) { await ApplyLayout(incrementalNodes); } }
/// <summary> /// Separates an aggregated aggregation node and replaces it by a new aggregation node. /// </summary> /// <remarks> /// Creates hierarchy edges between the new aggregation node and its children. /// </remarks> /// <param name="node">The node.</param> /// <returns>The nodes affected by this operation. The created aggregation node is always the first item.</returns> public IListEnumerable <INode> Separate(INode node) { var aggregationInfo = (AggregationNodeInfo)node.Tag; var aggregate = aggregationInfo.Aggregate; var aggregatedItems = AggregateGraph.GetAggregatedItems(node) .Where(n => n != aggregate.Node) .Cast <INode>().ToList(); AggregateGraph.Separate(node); var nodesToAggregate = aggregate.Node != null ? new ListEnumerable <INode>(new List <INode> { aggregate.Node }) : ListEnumerable <INode> .Empty; var aggregationNode = AggregateGraph.Aggregate(nodesToAggregate, node.Layout.ToRectD(), AggregationNodeStyle); foreach (var child in aggregatedItems) { AggregateGraph.CreateEdge(aggregationNode, child, HierarchyEdgeStyle, true); AggregateGraph.SetNodeLayout(child, RectD.FromCenter(aggregationNode.Layout.GetCenter(), child.Layout.ToSizeD())); ReplaceEdges(child); } aggregationInfo.IsAggregated = false; aggregateToNode[aggregate] = aggregationNode; aggregationNode.Tag = aggregationInfo; var affectedNodes = new List <INode> { aggregationNode }; affectedNodes.AddRange(aggregatedItems); if (aggregate.Parent != null && aggregateToNode.TryGetValue(aggregate.Parent, out var parentNode)) { AggregateGraph.CreateEdge(parentNode, aggregationNode, HierarchyEdgeStyle, true); affectedNodes.Add(parentNode); } if (aggregate.Node != null) { placeholderMap[aggregate.Node] = aggregationNode; CopyLabels(aggregate.Node, aggregationNode); ReplaceEdges(aggregationNode); } return(new ListEnumerable <INode>(affectedNodes)); }
// Creates a node and sets it's correct size private INode CreateNode(IInputModeContext context, IGraph graph, PointD location, INode parent) { INode node = graph.CreateNode(location); node.Tag = CreateDefaultClassInfo(); var style = node.Style as NodeControlNodeStyle; if (style != null) { SizeD size = style.GetPreferredSize(graphControl.CreateRenderContext(), node); graph.SetNodeLayout(node, RectD.FromCenter(location, new SizeD(120, size.Height))); } return(node); }
/// <summary> /// Sets the original node bounds according to the given anchor location and size. /// </summary> private RectD SetNodeLocationAndSize(IInputModeContext inputModeContext, PointD anchor, SizeD size) { var graph = inputModeContext.GetGraph(); if (graph == null) { return(RectD.Empty); } var orientedRectangle = new OrientedRectangle(anchor.X, anchor.Y, size.Width, size.Height, initialLayout.UpX, initialLayout.UpY); var center = orientedRectangle.GetCenter(); var layout = RectD.FromCenter(center, size); graph.SetNodeLayout(node, layout); return(layout); }
/// <summary> /// Initializes the graph instance setting default styles /// and creating a small sample graph. /// </summary> protected virtual void InitializeGraph() { IGraph graph = graphControl.Graph; // set the style as the default for all new nodes graph.NodeDefaults.Style = defaultStyle; graph.NodeDefaults.Size = new SizeD(100, 60); DefaultLabelStyle labelStyle = new DefaultLabelStyle(); labelStyle.Typeface = new Typeface("Arial"); labelStyle.BackgroundBrush = Brushes.LightBlue; // set the style as the default for all new node labels graph.NodeDefaults.Labels.Style = labelStyle; graph.CreateNode(RectD.FromCenter(new PointD(200, 100), graph.NodeDefaults.Size), graph.NodeDefaults.GetStyleInstance(), new MyBusinessObject(0.3)); }
/// <summary> /// Initializes the graph instance setting default styles /// and creating a small sample graph. /// </summary> protected virtual void InitializeGraph() { IGraph graph = graphControl.Graph; // set the style as the default for all new nodes graph.NodeDefaults.Style = defaultStyle; graph.NodeDefaults.Size = new SizeD(100, 60); DefaultLabelStyle labelStyle = new DefaultLabelStyle(); Font font = new Font(FontFamily.GenericSansSerif, 12, GraphicsUnit.Pixel); labelStyle.Font = font; labelStyle.BackgroundBrush = Brushes.LightBlue; // set the style as the default for all new node labels graph.NodeDefaults.Labels.Style = labelStyle; graph.CreateNode(RectD.FromCenter(new PointD(200, 100), graph.NodeDefaults.Size), graph.NodeDefaults.GetStyleInstance(), new MyBusinessObject(0.3)); }
private NodeCreationCallback GetNodeCreator(NodeCreationCallback nodeCreator) { return((context, graph, location, parent) => { INode paletteNode = styleListBox.SelectedItem as INode; if (paletteNode != null) { if (paletteNode.Tag == null || !paletteNode.Tag.ToString().EndsWith("Label Container")) { INode newNode = nodeCreator(context, graph, location, parent); graph.SetStyle(newNode, paletteNode.Style); graph.SetNodeLayout(newNode, RectD.FromCenter(location, paletteNode.Layout.ToSizeD())); graph.SetIsGroupNode(newNode, paletteNode.Style is PanelNodeStyle); foreach (var label in paletteNode.Labels) { graph.AddLabel(newNode, label.Text, label.LayoutParameter, label.Style); } return newNode; } } return null; }); }
/// <summary> /// Paint the node style representation. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void nodeStyleListBox_DrawItem(object sender, DrawItemEventArgs e) { ListBox listBox = (ListBox)sender; int i = e.Index; INode node = (INode)listBox.Items[i]; node = new SimpleNode { Labels = node.Labels, Layout = node.Layout, Style = node.Style, Tag = node.Tag }; if (node.Layout.Height > 50) { ((SimpleNode)node).Layout = RectD.FromCenter(node.Layout.GetCenter(), new SizeD(20, 30)); } Rectangle bounds = e.Bounds; Rectangle insets = Rectangle.FromLTRB(5, 5, 5, 25); Graphics g = e.Graphics; SmoothingMode oldMode = g.SmoothingMode; Region oldClip = g.Clip; // in .net 3.5 there are repaint issues - none of the below seems to help, there // are still sometimes background rendering artifacts left over. g.IntersectClip(bounds); g.FillRegion(new SolidBrush(e.BackColor), g.Clip); g.Clear(e.BackColor); e.DrawBackground(); var sx = (float)((bounds.Width - insets.Left - insets.Right) / node.Layout.Width); var sy = (float)((bounds.Height - insets.Top - insets.Bottom) / node.Layout.Height); if (sx > 0 && sy > 0) { var transform = g.Transform; g.SmoothingMode = SmoothingMode.HighQuality; g.TranslateTransform((float)(bounds.X + insets.Left), (float)(bounds.Y + insets.Top)); g.ScaleTransform(Math.Min(sx, sy), Math.Min(sx, sy)); g.TranslateTransform((float)(-node.Layout.X), (float)(-node.Layout.Y)); //Get the renderer from the style, this requires the dummy node instance. var renderContext = new RenderContext(g, null) { ViewTransform = g.Transform, WorldTransform = g.Transform }; node.Style.Renderer.GetVisualCreator(node, node.Style).CreateVisual(renderContext).Paint(renderContext, g); var lgns = node.Style as LogicGateNodeStyle; if (lgns != null) { g.DrawString(lgns.GateType.ToString(), new Font("Arial", 8.25f), Brushes.Black, -10, 20); } else if (node.Labels.Any()) { g.DrawString(node.Labels.First().Text.Replace("\n", " "), new Font("Arial", 8.25f), Brushes.Black, -10, 20); } g.Transform = transform; g.SmoothingMode = oldMode; } g.Clip = oldClip; e.DrawFocusRectangle(); }
public IVisual UpdateVisual(IRenderContext context, IVisual oldVisual) { rectangle.Reshape(RectD.FromCenter(Center, new SizeD(PageWidth + Margin, PageHeight + Margin))); return(oldVisual); }
/// <summary> /// Calculates the bounds of this port. /// </summary> /// <remarks> /// These are also used for arranging the visual, hit testing, visibility testing, and marquee box tests. /// </remarks> protected override RectD GetBounds(ICanvasContext context, IPort port) { return(RectD.FromCenter(port.GetLocation(), new SizeD(Width, Height))); }
public override void SetBounds(IRectangle bounds) { base.SetBounds(RectD.FromCenter(bounds.GetCenter(), combinedSize)); }