/// <summary> /// Returns the connector starting coordinates. /// </summary> /// <param name="info">Connector display information.</param> /// <returns>Point object.</returns> protected 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> /// 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; DrawStarConnector(info); }
private void DrawStarConnector(ConnectorRendererEventArgs info) { Point pStart=this.GetStartPoint(info); Point[] parr=this.GetEndPoint(info); Point pEnd=parr[0]; Point pEndUnderLine=parr[1]; if(info.ConnectorPoints==null) { // Determine whether curve can be drawn if(Math.Abs(pStart.X-pEnd.X)<=6 || Math.Abs(pStart.Y-pEnd.Y)<=10) { DrawLineConnector(info,pStart,pEnd,pEndUnderLine); } else { Point pBottom=new Point(); Point pTop=new Point(); if(pEnd.X<pStart.X) { pBottom.X=pStart.X-info.NodeConnector.LineWidth; pTop.X=pEnd.X+1; } else { pBottom.X=pStart.X+info.NodeConnector.LineWidth; pTop.X=pEnd.X-1; } pBottom.Y=pStart.Y; pTop.Y=pEnd.Y; GraphicsPath path=new GraphicsPath(); path.AddLine(pStart,pBottom); path.AddLine(pBottom,pEnd); path.AddLine(pEnd,pTop); path.AddLine(pTop,pStart); path.CloseAllFigures(); using(Brush brush=this.GetLineBrush(info)) info.Graphics.FillPath(brush,path); } } else { ConnectorPointInfo pointInfo=GetConnectorPointInfo(info,pStart,pEnd); if(pointInfo.Points2==null) { using(Pen pen=this.GetLinePen(info)) { info.Graphics.DrawLines(pen,pointInfo.Points1); } } else { using(GraphicsPath path=new GraphicsPath()) { path.AddLines(pointInfo.Points1); path.AddLines(pointInfo.Points2); path.CloseAllFigures(); using(Brush brush=this.GetLineBrush(info)) { info.Graphics.FillPath(brush,path); } } } } DrawEndLine(info,pStart,pEnd,pEndUnderLine); }
internal virtual ConnectorPointInfo GetConnectorPointInfo(ConnectorRendererEventArgs info, Point pStart, Point pEnd) { ConnectorPointInfo pointInfo=new ConnectorPointInfo(); int xMulti=1/*, yMulti=1*/; int lineWidth=info.NodeConnector.LineWidth; // used for direction control if(pStart.X>pEnd.X) xMulti=-1; //if(pStart.Y>pEnd.Y) // yMulti=-1; if(info.ConnectorPoints!=null) { Point connPointsOffset=info.ToNode.BoundsRelative.Location; connPointsOffset.Offset(info.Offset.X,info.Offset.Y); GraphicsPath path=new GraphicsPath(); pointInfo.Points1=new Point[info.ConnectorPoints.Count+2]; pointInfo.Points1[0]=pStart; pointInfo.Points1[pointInfo.Points1.Length-1]=pEnd; if(lineWidth>1) { pointInfo.Points2=new Point[info.ConnectorPoints.Count+2]; pointInfo.Points2[pointInfo.Points2.Length-1]=pStart; pointInfo.Points2[0]=pEnd; int i=pointInfo.Points1.Length-2; int k=1; foreach(Point pcp in info.ConnectorPoints) { pointInfo.Points1[i]=pcp; pointInfo.Points1[i].Offset(connPointsOffset.X,connPointsOffset.Y); pointInfo.Points2[k]=new Point(pcp.X+lineWidth*xMulti,pcp.Y); pointInfo.Points2[k].Offset(connPointsOffset.X,connPointsOffset.Y); k++; i--; } } else { int i=pointInfo.Points1.Length-2; foreach(Point pcp in info.ConnectorPoints) { pointInfo.Points1[i]=pcp; pointInfo.Points1[i].Offset(connPointsOffset.X,connPointsOffset.Y); i--; } } } return pointInfo; }
protected void DrawEndLine(ConnectorRendererEventArgs info,Point pStart,Point pEnd,Point pEndUnderLine) { if(pEndUnderLine.IsEmpty) { switch(info.NodeConnector.EndCap) { case eConnectorCap.Ellipse: { using(Pen pen=this.GetEndLinePen(info)) { Size endCapSize=info.NodeConnector.EndCapSize; if(pStart.X<pEnd.X) info.Graphics.DrawEllipse(pen,pEnd.X-1,pEnd.Y-endCapSize.Height/2,endCapSize.Width,endCapSize.Height); else info.Graphics.DrawEllipse(pen,pEnd.X-endCapSize.Width,pEnd.Y-endCapSize.Height/2,endCapSize.Width,endCapSize.Height); } break; } case eConnectorCap.Arrow: { using(Pen pen=this.GetEndLinePen(info)) { // Connects connector line to arrow int direction=1; if(pStart.X>pEnd.X) direction=-1; info.Graphics.DrawLine(pen,pEnd,new Point(pEnd.X+info.NodeConnector.EndCapSize.Width/3*direction,pEnd.Y)); Size endCapSize=info.NodeConnector.EndCapSize; GraphicsPath arrow=GetArrowPath(endCapSize,pStart,pEnd); info.Graphics.DrawPath(pen,arrow); } break; } } } else { using(Pen pen=this.GetEndUnderlinePen(info)) { info.Graphics.DrawLine(pen,pEnd,pEndUnderLine); // Connect underline to expand part if(NodeDisplay.DrawExpandPart(info.ToNode)) { Rectangle re=NodeDisplay.GetNodeRectangle(eNodeRectanglePart.ExpandBounds,info.ToNode,info.Offset); Point p2=new Point((re.X>pEndUnderLine.X?re.X:re.Right)+(re.Width/2*(re.X>pEndUnderLine.X?1:-1)),re.Bottom); Point p1=new Point(p2.X,pEndUnderLine.Y+(pEndUnderLine.Y>p2.Y?(p2.Y-pEndUnderLine.Y)/2:-(p2.Y-pEndUnderLine.Y)/2)); info.Graphics.DrawCurve(pen,new Point[]{pEndUnderLine,p1,p2},.5f); } } } }
/// <summary> /// Draws connector line between two nodes. /// </summary> /// <param name="info">Connector context information.</param> public virtual void DrawConnector(ConnectorRendererEventArgs info){}
protected Brush GetLineBrush(ConnectorRendererEventArgs info) { return new SolidBrush(info.NodeConnector.LineColor); }
/// <summary> /// Returns new instance of pen object for the node underline 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 GetEndUnderlinePen(ConnectorRendererEventArgs info) { return new Pen(info.NodeConnector.LineColor,EndLineWidth); }
/// <summary> /// Draws straight line connector between start and end point. /// </summary> /// <param name="info">Node connector display info.</param> /// <param name="pStart">Start point.</param> /// <param name="pEnd">End point.</param> /// <param name="pEndUnderLine">Underline end point if any.</param> protected void DrawLineConnector(ConnectorRendererEventArgs info,Point pStart,Point pEnd, Point pEndUnderLine) { if(info.NodeConnector.LineWidth>1) { // Merge lines nicely by filling and creating path... int rootLineWidth=this.EndLineWidth; int lineWidth=info.NodeConnector.LineWidth; using(Brush brush=GetLineBrush(info)) { GraphicsPath path=GetConnectingPath(pStart,pEnd,lineWidth,rootLineWidth,info.IsRootNode,!(IsAbove(info.FromNode,info.ToNode) || IsBelow(info.FromNode,info.ToNode))); info.Graphics.FillPath(brush,path); } } else { using(Pen pen=this.GetLinePen(info)) { info.Graphics.DrawLine(pen,pStart,pEnd); } } if(!pEndUnderLine.IsEmpty) { using(Pen pen=this.GetEndUnderlinePen(info)) { info.Graphics.DrawLine(pen,pEnd,pEndUnderLine); } } }
/// <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=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> /// 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 override void DrawConnector(ConnectorRendererEventArgs e) { NodeConnectorDisplay display = GetConnectorDisplay(e.NodeConnector); if(display!=null) display.DrawConnector(e); base.DrawConnector(e); }
private void DrawCurveConnector(ConnectorRendererEventArgs info) { Point pStart=this.GetStartPoint(info); Point[] parr=this.GetEndPoint(info); Point pEnd=parr[0]; Point pEndUnderLine=parr[1]; int lineWidth=info.NodeConnector.LineWidth; int xMulti=1, yMulti=1; // used for direction control if(pStart.X>pEnd.X) xMulti=-1; if(pStart.Y>pEnd.Y) yMulti=-1; if(info.ConnectorPoints==null || info.ConnectorPoints.Count == 0) { // Determine whether curve can be drawn if(Math.Abs(pStart.X-pEnd.X)<=6 || Math.Abs(pStart.Y-pEnd.Y)<=10) { DrawLineConnector(info,pStart,pEnd,pEndUnderLine); } else { // Create two points in between the start and end point Point[] p=new Point[4]; p[1].X=pStart.X+(int)(Math.Abs(pStart.X-pEnd.X)*.15f*xMulti); p[1].Y=pStart.Y+(int)(Math.Abs(pStart.Y-pEnd.Y)*.15f*yMulti); p[2].X=pStart.X+(int)(Math.Abs(pStart.X-pEnd.X)*.5f*xMulti); p[2].Y=pEnd.Y-(int)(yMulti*(Math.Abs(pStart.Y-pEnd.Y)*.15f)); p[0]=pStart; p[3]=pEnd; if(lineWidth>1) { GraphicsPath path=new GraphicsPath(); path.AddCurve(p,.5f); // Check whether pStart is starting from left or right side Rectangle fromNodeRect=info.FromNode.BoundsRelative; fromNodeRect.Offset(info.Offset); fromNodeRect.Inflate(-1,-1); // if(pStart.Y>fromNodeRect.Y && pStart.Y<fromNodeRect.Bottom && pStart.X>=fromNodeRect.Right) // { // path.AddLine(pStart.X, pStart.Y-lineWidth*xMulti, pStart.X, pStart.Y); // } path.AddLine(p[0].X,p[0].Y,p[0].X+lineWidth*xMulti,p[0].Y); if(pStart.Y>fromNodeRect.Y && pStart.Y<fromNodeRect.Bottom && pStart.X>=fromNodeRect.Right && info.IsRootNode) { path.AddLine(p[0].X-1,p[0].Y,p[0].X-1,p[0].Y+lineWidth*yMulti); p[0].Y -= lineWidth*yMulti; } else if(pStart.Y>fromNodeRect.Y && pStart.Y<fromNodeRect.Bottom && pStart.X<=fromNodeRect.Left && info.IsRootNode) { path.AddLine(p[0].X+1,p[0].Y,p[0].X+1,p[0].Y+lineWidth*yMulti); p[0].Y -= lineWidth*yMulti; } else p[0].X+=(lineWidth*xMulti); p[1].X+=(lineWidth*xMulti); p[2].X+=(lineWidth*xMulti); p[3].Y-=yMulti; path.AddCurve(p,.5f); path.AddLine(p[3].X,p[3].Y,p[3].X,p[3].Y+yMulti); path.CloseAllFigures(); using(Brush brush=this.GetLineBrush(info)) { info.Graphics.FillPath(brush,path); } } else { using(Pen pen=this.GetLinePen(info)) { info.Graphics.DrawCurve(pen,p,.5f); } } } } else { ConnectorPointInfo pointInfo=GetConnectorPointInfo(info,pStart,pEnd); if(pointInfo.Points2==null) { using(Pen pen=this.GetLinePen(info)) { info.Graphics.DrawCurve(pen,pointInfo.Points1,.5f); } } else { using(GraphicsPath path=new GraphicsPath()) { path.AddCurve(pointInfo.Points1,.5f); path.AddCurve(pointInfo.Points2,.5f); path.CloseAllFigures(); using(Brush brush=this.GetLineBrush(info)) { info.Graphics.FillPath(brush,path); } } } } DrawEndLine(info,pStart,pEnd,pEndUnderLine); }
/// <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); }