/// <summary> /// Draws connector line between two nodes. /// </summary> /// <param name="info">Connector context information.</param> public override void DrawConnector(ConnectorRendererEventArgs info) { if(info.NodeConnector.LineColor.IsEmpty || info.NodeConnector.LineWidth<=0) return; Point pStart, pEnd; // FromNode is null when connector is rendered for the child node if (info.FromNode == null) { Rectangle cellBounds = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeContentBounds, info.ToNode, info.Offset); Rectangle expandBounds = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.ExpandBounds, info.ToNode, info.Offset); pStart = new Point(cellBounds.X - 4, cellBounds.Y + cellBounds.Height / 2); pEnd = new Point(expandBounds.X + expandBounds.Width / 2, pStart.Y); } else { // FromNode is parent node, ToNode is last visible child node. Connector is vertical line from parent to last visible child Rectangle cellBounds = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeContentBounds, info.FromNode, info.Offset); Rectangle expandBounds = NodeDisplay.GetNodeRectangle(eNodeRectanglePart.ExpandBounds, info.ToNode, info.Offset); pStart = new Point(expandBounds.X + expandBounds.Width / 2, cellBounds.Bottom); pEnd = new Point(pStart.X, expandBounds.Y + expandBounds.Height / 2); } Graphics g = info.Graphics; using (Pen pen = GetLinePen(info)) { SmoothingMode sm = g.SmoothingMode; if (pen.DashStyle != DashStyle.Solid) g.SmoothingMode = SmoothingMode.Default; g.DrawLine(pen, pStart, pEnd); g.SmoothingMode = sm; } }
/// <summary> /// Raises RenderConnector event. /// </summary> /// <param name="e">Event data.</param> protected virtual void OnRenderConnector(ConnectorRendererEventArgs e) { if(RenderConnector!=null) RenderConnector(this, e); }
/// <summary> /// Draws connector between nodes. If you need to provide custom rendering this is the method that you should override in your custom rendered. If you /// do not want default rendering to occur do not call the base implementation. You can call OnRenderConnector method so events can occur. /// </summary> /// <param name="e">Information provided for rendering.</param> public virtual void DrawConnector(ConnectorRendererEventArgs e) { OnRenderConnector(e); }
/// <summary> /// Draws connector line between two nodes. /// </summary> /// <param name="info">Connector context information.</param> public virtual void DrawConnector(ConnectorRendererEventArgs info){}
///// <summary> ///// Returns the connector starting coordinates. ///// </summary> ///// <param name="info">Connector display information.</param> ///// <returns>Point object.</returns> //protected virtual Point GetStartPoint(ConnectorRendererEventArgs info) //{ // Point p=Point.Empty; // if(info.IsRootNode) // { // //int toMidPoint=info.ToNode.Bounds.Top+info.ToNode.Bounds.Height/2; // //if(info.FromNode.Bounds.Top>toMidPoint) // if(IsAbove(info.FromNode,info.ToNode)) // p=new Point(info.FromNode.BoundsRelative.Left+info.FromNode.BoundsRelative.Width/2,info.FromNode.BoundsRelative.Top); // //else if(info.FromNode.Bounds.Bottom<toMidPoint) // else if(IsBelow(info.FromNode,info.ToNode)) // p=new Point(info.FromNode.BoundsRelative.Left+info.FromNode.BoundsRelative.Width/2,info.FromNode.BoundsRelative.Bottom-1); // } // if(p.IsEmpty) // { // // To element to the Left // if(this.IsOnLeftSide(info.FromNode,info.ToNode)) // p=new Point(info.FromNode.BoundsRelative.Left,info.FromNode.BoundsRelative.Top+info.FromNode.BoundsRelative.Height/2); // else // { // p=new Point(info.FromNode.BoundsRelative.Right,info.FromNode.BoundsRelative.Top+info.FromNode.BoundsRelative.Height/2); // if(info.IsRootNode) // p.X--; // if(!NodeDisplay.DrawExpandPart(info.FromNode) && info.FromNode.ExpandVisibility==eNodeExpandVisibility.Auto) // p.X-=(info.FromNode.BoundsRelative.Width-info.FromNode.ContentBounds.Width); // } // } // if(!p.IsEmpty) // p.Offset(info.Offset.X,info.Offset.Y); // return p; //} ///// <summary> ///// Returns true if fromNode is above the toNode. ///// </summary> ///// <param name="fromNode">From Node object.</param> ///// <param name="toNode">To Node object</param> ///// <returns>True if fromNode is above toNode.</returns> //protected bool IsAbove(Node fromNode, Node toNode) //{ // //int toMidPoint=toNode.Bounds.Top+toNode.Bounds.Height/2; // //if(fromNode.Bounds.Top>toMidPoint) // if(fromNode.BoundsRelative.Top>toNode.BoundsRelative.Bottom) // return true; // return false; //} ///// <summary> ///// Returns true if fromNode is below toNode. ///// </summary> ///// <param name="fromNode">From Node object.</param> ///// <param name="toNode">To Node object.</param> ///// <returns>True if fromNode is below toNode.</returns> //protected bool IsBelow(Node fromNode, Node toNode) //{ // int toMidPoint=toNode.BoundsRelative.Top+toNode.BoundsRelative.Height/2; // if(fromNode.BoundsRelative.Bottom<toMidPoint) // return true; // return false; //} ///// <summary> ///// Returns whether connector is extended to underline the node. ///// </summary> ///// <param name="nodeStyle">Refernce to Node style.</param> ///// <returns>True if node should be underlined by connector.</returns> //protected bool UnderlineNode(ElementStyle nodeStyle) //{ // if(!nodeStyle.PaintBottomBorder && !nodeStyle.PaintTopBorder && // !nodeStyle.PaintLeftBorder && !nodeStyle.PaintRightBorder) // return true; // return false; //} ///// <summary> ///// Returns the connector end point. The array of end points. Two valid points will be returned if node needs to be underlined by connector. ///// </summary> ///// <param name="info">Connector display info.</param> ///// <returns>Array of point objects.</returns> //protected Point[] GetEndPoint(ConnectorRendererEventArgs info) //{ // // If to element is to the right of the from node and has left border end point is the vertical mid-point // // If to element is to the left of the from node and has right border end point is the vertical mid-point // // If there is no border end point is text bottom // // If this is link connector the end point is the middle bottom or top point of the node // Point p=Point.Empty; // Point pLineEnd=Point.Empty; // int capWidthOffset = 0; // GetCapWidthOffset(info.NodeConnector.EndCap, info.NodeConnector.EndCapSize); // bool leftSide=this.IsOnLeftSide(info.FromNode,info.ToNode); // if(info.LinkConnector && info.FromNode.BoundsRelative.Top>info.ToNode.BoundsRelative.Bottom) // p=new Point(info.ToNode.BoundsRelative.X+info.ToNode.BoundsRelative.Width/2+(leftSide?capWidthOffset:-capWidthOffset),info.ToNode.BoundsRelative.Bottom+1); // else if(info.LinkConnector && info.FromNode.BoundsRelative.Bottom<info.ToNode.BoundsRelative.Top) // p=new Point(info.ToNode.BoundsRelative.X+info.ToNode.BoundsRelative.Width/2+(leftSide?capWidthOffset:-capWidthOffset),info.ToNode.BoundsRelative.Top-info.NodeConnector.EndCapSize.Height); // else // { // if(leftSide) // { // // To element is to the left of from node // Rectangle r=info.ToNode.BoundsRelative; // if(info.StyleToNode==null || UnderlineNode(info.StyleToNode)) // { // p=new Point(r.Right,r.Bottom); // if(m_EndCap) // p.X+=capWidthOffset; // if(info.NodeConnector.UnderlineNoBorderNode) // { // Rectangle rc=NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeContentBounds,info.ToNode,Point.Empty); // pLineEnd=new Point(rc.Left+1,r.Bottom); // } // } // else // { // p=new Point(r.Right,r.Y+r.Height/2); // if(m_EndCap) // p.X+=capWidthOffset; // } // } // else // { // // To element to the right of from node // Rectangle r=info.ToNode.BoundsRelative; // if(info.StyleToNode==null || UnderlineNode(info.StyleToNode)) // { // //r=NodeDisplay.GetCellRectangle(eCellRectanglePart.TextBounds,info.ToNode.Cells[0],Point.Empty); // //r=info.ToNode.Cells[0].TextContentBounds; // p=new Point(r.X,r.Bottom); // if(m_EndCap) // p.X-=capWidthOffset; // if(info.NodeConnector.UnderlineNoBorderNode) // { // Rectangle rc=NodeDisplay.GetNodeRectangle(eNodeRectanglePart.NodeContentBounds,info.ToNode,Point.Empty); // pLineEnd=new Point(rc.Right-1,r.Bottom); // } // } // else // { // p=new Point(r.X,r.Y+r.Height/2); // if(m_EndCap) // p.X-=capWidthOffset; // } // } // } // if(!p.IsEmpty) // p.Offset(info.Offset.X,info.Offset.Y); // if(!pLineEnd.IsEmpty) // pLineEnd.Offset(info.Offset.X,info.Offset.Y); // return new Point[] {p,pLineEnd}; //} ///// <summary> ///// Returns the offest for the node connector cap. ///// </summary> ///// <param name="cap">Cap type.</param> ///// <param name="size">Cap size.</param> ///// <returns></returns> //protected int GetCapWidthOffset(eConnectorCap cap,Size size) //{ // int capWidthOffset=0; // switch(cap) // { // case eConnectorCap.Arrow: // capWidthOffset=size.Width+1; // break; // case eConnectorCap.Ellipse: // capWidthOffset=size.Width; // break; // } // return capWidthOffset; //} ///// <summary> ///// Returns true if source node is on the left side of the target node. ///// </summary> ///// <param name="source">Reference to source node.</param> ///// <param name="target">Reference to target node.</param> ///// <returns>True if source is on the left side of target.</returns> //protected bool IsOnLeftSide(Node source, Node target) //{ // if((source.BoundsRelative.Left+source.BoundsRelative.Width/2)>target.BoundsRelative.Left) // return true; // return false; //} /// <summary> /// Returns new instance of pen object for node connector line. Caller is responsible for /// disposing of this object. /// </summary> /// <param name="info">Node connector display info.</param> /// <returns>New instance of Pen object.</returns> protected Pen GetLinePen(ConnectorRendererEventArgs info) { Pen pen = new Pen(info.NodeConnector.LineColor, info.NodeConnector.LineWidth); pen.DashStyle = info.NodeConnector.DashStyle; return pen; }