private void CreateNodesAndLinks(IEnumerable <SankeyData> datas)
        {
            currentSliceNodes = new List <SankeyNode>();
            currentLinks      = new List <SankeyLink>();
            styleManager.DefaultNodeLinksPaletteIndex = 0;

            foreach (var data in datas)
            {
                if (!currentSliceNodes.Exists(n => n.Name == data.From))
                {
                    currentSliceNodes.Add(CreateNode(data, data.From));
                }

                if (!currentSliceNodes.Exists(n => n.Name == data.To))
                {
                    currentSliceNodes.Add(CreateNode(data, data.To));
                }

                var fromNode = currentSliceNodes.Find(findNode => findNode.Name == data.From);

                if (fromNode != null)
                {
                    var toNode = currentSliceNodes.Find(findNode => findNode.Name == data.To);

                    if (toNode != null)
                    {
                        // merge links which has the same from & to
                        if (currentLinks != null)
                        {
                            var previousLink = currentLinks.Find(findLink => findLink.FromNode.Name == fromNode.Name && findLink.ToNode.Name == toNode.Name);

                            if (previousLink != null)
                            {
                                previousLink.Weight += data.Weight;

                                continue;
                            }
                        }

                        // create link
                        var shape = new Path();
                        shape.MouseEnter        += LinkMouseEnter;
                        shape.MouseLeave        += LinkMouseLeave;
                        shape.MouseLeftButtonUp += LinkMouseLeftButtonUp;
                        shape.Tag  = new SankeyLinkFinder(data.From, data.To);
                        shape.Fill = diagram.UsePallette != SankeyPalette.None ? fromNode.Shape.Fill.CloneCurrentValue() : data.LinkBrush == null?styleManager.DefaultLinkBrush.CloneCurrentValue() : data.LinkBrush.CloneCurrentValue();

                        var link = new SankeyLink(fromNode, toNode, shape, data.Weight, shape.Fill.CloneCurrentValue());
                        fromNode.OutLinks.Add(link);
                        toNode.InLinks.Add(link);
                        currentLinks.Add(link);
                    }
                }
            }
        }
        private void RecoverHighlights(SankeyLink link, bool resetHighlightStatus = true)
        {
            link.Shape.Fill           = link.OriginalBrush.CloneCurrentValue();
            link.FromNode.Shape.Fill  = link.FromNode.OriginalBrush.CloneCurrentValue();
            link.ToNode.Shape.Fill    = link.ToNode.OriginalBrush.CloneCurrentValue();
            link.ToNode.Label.Style   = link.FromNode.Label.Style = diagram.LabelStyle;
            link.ToNode.Label.Opacity = link.FromNode.Label.Opacity = OriginalLabelOpacity;

            if (resetHighlightStatus)
            {
                link.IsHighlight          = false;
                link.FromNode.IsHighlight = false;
                link.ToNode.IsHighlight   = false;
            }
        }
        private SankeyLink DrawLink(SankeyLink link)
        {
            // create tooltip
            var toolTip = new ToolTip();

            toolTip.Template    = diagram.ToolTipTemplate;
            link.Shape.ToolTip  = toolTip;
            toolTip.DataContext = link;

            var startPoint           = new Point();
            var line1EndPoint        = new Point();
            var bezier1ControlPoint1 = new Point();
            var bezier1ControlPoint2 = new Point();
            var bezier1EndPoint      = new Point();
            var line2EndPoint        = new Point();
            var bezier2ControlPoint1 = new Point();
            var bezier2ControlPoint2 = new Point();

            if (diagram.SankeyFlowDirection == FlowDirection.TopToBottom)
            {
                line1EndPoint.Y        = startPoint.Y = link.FromNode.Y + link.FromNode.Shape.Height;
                bezier2ControlPoint2.X = startPoint.X = link.FromNode.X + link.FromPosition;
                bezier1ControlPoint1.X = line1EndPoint.X = startPoint.X + link.Width;
                line2EndPoint.Y        = bezier1EndPoint.Y = link.ToNode.Y;
                bezier2ControlPoint1.X = line2EndPoint.X = link.ToNode.X + link.ToPosition;
                bezier1ControlPoint2.X = bezier1EndPoint.X = line2EndPoint.X + link.Width;
                var length = line2EndPoint.Y - line1EndPoint.Y;
                bezier2ControlPoint2.Y = bezier1ControlPoint1.Y = diagram.LinkCurvature * length + startPoint.Y;
                bezier2ControlPoint1.Y = bezier1ControlPoint2.Y = (1 - diagram.LinkCurvature) * length + startPoint.Y;
            }
            else
            {
                line1EndPoint.X        = startPoint.X = link.FromNode.X + link.FromNode.Shape.Width;
                bezier2ControlPoint2.Y = startPoint.Y = link.FromNode.Y + link.FromPosition;
                bezier1ControlPoint1.Y = line1EndPoint.Y = startPoint.Y + link.Width;
                line2EndPoint.X        = bezier1EndPoint.X = link.ToNode.X;
                bezier2ControlPoint1.Y = line2EndPoint.Y = link.ToNode.Y + link.ToPosition;
                bezier1ControlPoint2.Y = bezier1EndPoint.Y = line2EndPoint.Y + link.Width;
                var length = line2EndPoint.X - line1EndPoint.X;
                bezier2ControlPoint2.X = bezier1ControlPoint1.X = diagram.LinkCurvature * length + startPoint.X;
                bezier2ControlPoint1.X = bezier1ControlPoint2.X = (1 - diagram.LinkCurvature) * length + startPoint.X;
            }

            var geometry = new PathGeometry()
            {
                Figures = new PathFigureCollection()
                {
                    new PathFigure()
                    {
                        StartPoint = startPoint,

                        Segments = new PathSegmentCollection()
                        {
                            new LineSegment()
                            {
                                Point = line1EndPoint
                            },

                            new BezierSegment()
                            {
                                Point1 = bezier1ControlPoint1,
                                Point2 = bezier1ControlPoint2,
                                Point3 = bezier1EndPoint
                            },

                            new LineSegment()
                            {
                                Point = line2EndPoint
                            },

                            new BezierSegment()
                            {
                                Point1 = bezier2ControlPoint1,
                                Point2 = bezier2ControlPoint2,
                                Point3 = startPoint
                            }
                        }
                    },
                }
            };

            link.Shape.Data = geometry;

            return(link);
        }