using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace Tango.PPC.Common.Controls { /// /// Interaction logic for MultiPieChart.xaml /// public partial class MultiPieChart : UserControl { private const string DefaultDataBrush = "#939496"; #region dependency properties public static readonly DependencyProperty SizeProperty = DependencyProperty.Register( "Size", typeof( double ), typeof( MultiPieChart ), new PropertyMetadata( 100.0, OnPiePropertyChanged ) ); public static readonly DependencyProperty InnerPieSliceFillProperty = DependencyProperty.Register( "InnerPieSliceFill", typeof( Brush ), typeof( MultiPieChart ), new PropertyMetadata( CreateBrush( "#939496" ), OnPiePropertyChanged ) ); public static readonly DependencyProperty OuterPieSliceFillProperty = DependencyProperty.Register( "OuterPieSliceFill", typeof( Brush ), typeof( MultiPieChart ), new PropertyMetadata( CreateBrush( "#D0D1D3" ), OnPiePropertyChanged ) ); public static readonly DependencyProperty DataListProperty = DependencyProperty.Register( "DataList", typeof( IList ), typeof( MultiPieChart ), new PropertyMetadata( null, OnDataListPropertyChanged ) ); public static readonly DependencyProperty DataBrushesProperty = DependencyProperty.Register( "DataBrushes", typeof( MultiPieChartBrushCollection ), typeof( MultiPieChart ), new PropertyMetadata( new MultiPieChartBrushCollection(), OnPiePropertyChanged ) ); public double Size { get { return (double)GetValue( SizeProperty ); } set { SetValue( SizeProperty, value ); } } public Brush InnerPieSliceFill { get { return (Brush)GetValue( InnerPieSliceFillProperty ); } set { SetValue( InnerPieSliceFillProperty, value ); } } public Brush OuterPieSliceFill { get { return (Brush)GetValue( OuterPieSliceFillProperty ); } set { SetValue( OuterPieSliceFillProperty, value ); } } public IList DataList { get { return (IList)GetValue( DataListProperty ); } set { SetValue( DataListProperty, value ); } } public MultiPieChartBrushCollection DataBrushes { get { return (MultiPieChartBrushCollection)GetValue( DataBrushesProperty ); } set { SetValue( DataBrushesProperty, value ); } } #endregion #region constructor public MultiPieChart() { InitializeComponent(); this.Loaded += (_, __) => { CreatePieChart(); }; } #endregion #region overrides #endregion #region events private static void OnPiePropertyChanged( DependencyObject dep, DependencyPropertyChangedEventArgs ev ) { //var chart = (MultiPieChart)dep; //if ( chart.IsInitialized ) //{ // chart.CreatePieChart(); //} } private static void OnDataListPropertyChanged( DependencyObject dep, DependencyPropertyChangedEventArgs ev ) { var chart = (MultiPieChart)dep; var collection = ev.OldValue as INotifyCollectionChanged; if ( collection != null ) { collection.CollectionChanged -= chart.DataListCollectionChanged; } collection = ev.NewValue as INotifyCollectionChanged; if ( collection != null ) { collection.CollectionChanged += chart.DataListCollectionChanged; } } private void DataListCollectionChanged( object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs ) { //CreatePieChart(); } #endregion #region private methods private void CreatePieChart() { Size = ActualWidth; if ( _pieChartImage != null ) { if ( !double.IsNaN( Size ) && DataList != null && DataList.Any() ) { _pieChartImage.Width = _pieChartImage.Height = Width = Height = Size; var di = new DrawingImage(); _pieChartImage.Source = di; var dg = new DrawingGroup(); di.Drawing = dg; if ( DataList.Count > 1 ) { var total = DataList.Sum(); var startPoint = new Point( Width / 2, 0 ); double radians = 0; for ( int i = 0; i < DataList.Count; i++ ) { var data = DataList[i]; var dataBrush = GetBrushFromList( i ); var percentage = data / total; Point endPoint; var angle = 360 * percentage; if ( i + 1 == DataList.Count ) { endPoint = new Point( Width / 2, 0 ); } else { radians += ( Math.PI / 180 ) * angle; var endPointX = Math.Sin( radians ) * Height / 2 + Height / 2; var endPointY = Width / 2 - Math.Cos( radians ) * Width / 2; endPoint = new Point( endPointX, endPointY ); } dg.Children.Add( CreatePathGeometry( dataBrush, startPoint, endPoint, angle > 180 ) ); startPoint = endPoint; } } else { dg.Children.Add( CreateEllipseGeometry( GetBrushFromList( 0 ) ) ); } } else { _pieChartImage.Source = null; } } } private GeometryDrawing CreatePathGeometry( Brush brush, Point startPoint, Point arcPoint, bool isLargeArc ) { /* * * */ var midPoint = new Point( Width / 2, Height / 2 ); var drawing = new GeometryDrawing { Brush = brush }; var pathGeometry = new PathGeometry(); var pathFigure = new PathFigure { StartPoint = midPoint }; var ls1 = new LineSegment( startPoint, false ); var arc = new ArcSegment { SweepDirection = SweepDirection.Clockwise, Size = new Size( Width / 2, Height / 2 ), Point = arcPoint, IsLargeArc = isLargeArc }; var ls2 = new LineSegment( midPoint, false ); drawing.Geometry = pathGeometry; pathGeometry.Figures.Add( pathFigure ); pathFigure.Segments.Add( ls1 ); pathFigure.Segments.Add( arc ); pathFigure.Segments.Add( ls2 ); return drawing; } private GeometryDrawing CreateEllipseGeometry( Brush brush ) { var midPoint = new Point( Width / 2, Height / 2 ); var drawing = new GeometryDrawing { Brush = brush }; var ellipse = new EllipseGeometry( midPoint, Size / 2, Size / 2 ); drawing.Geometry = ellipse; return drawing; } private static SolidColorBrush CreateBrush( string brush ) { var color = ColorConverter.ConvertFromString( brush ); if ( color != null ) { return new SolidColorBrush( (Color)color ); } return null; } private Brush GetBrushFromList( int index ) { if ( DataBrushes == null || !DataBrushes.Any() ) { return CreateBrush( DefaultDataBrush ); } else { var modIndex = index % DataBrushes.Count; return DataBrushes[modIndex]; } } #endregion } }