내용으로 건너뛰기
How To Build XAML Doughnut Chart?

How To Build XAML Doughnut Chart?

WPF 및 Silverlight 용 Infragistics 패키지에는 데이터 시각화를 위한 다양한 차트가 포함되어 있습니다. 우리가 살펴볼 컨트롤은 도넛 차트.

8min read

이 차트는 빈 중심을 둘러싼 하나 이상의 고리를 지원합니다. 슬라이스, 레이블 및 색상을 제어하거나 내부 반경을 구성하여 사용자 지정할 수 있습니다. 이 블로그에서는 이 컨트롤을 애플리케이션에 추가하는 방법과 여러 링을 사용하여 사용자 지정 계층적 차트를 만드는 방법을 알아볼 수 있습니다.

XAML Doughnut Chart with custom brushes

Adding the Doughnut Chart

일반적으로 WPF 프로젝트를 만들 때 가장 먼저 해야 할 일은 참조를 추가하는 것입니다. 그렇게 하는 쉬운 방법이 있습니다.

  1. 도구 상자로 이동합니다. 여기에서 NetAdvantage WPF 및 Shared XAML 컨트롤을 볼 수 있습니다.
  2. Drag and drop the “XamDoughnutChart”.

이러한 단계를 수행하면 Visual Studio에서 필요한 Infragistics 참조를 자동으로 추가하는 것을 볼 수 있습니다.

이러한 단계를 수행하면 Visual Studio에서 필요한 Infragistics 참조를 자동으로 추가하는 것을 볼 수 있습니다.

"XamDoughnutChart"를 드래그하면 실제로 차트를 호스팅하는 데 필요한 태그가 생성되었습니다. 다음 단계는 다음 코드를 포함하는 것입니다.

<ig:XamDoughnutChart x:Name="slice">
    <ig:XamDoughnutChart.Series>
        <ig:RingSeries
            LabelMemberPath="Label"
            ValueMemberPath="productionShare"
            LabelsPosition="BestFit"
            ItemsSource="{Binding Mode=OneWay, Source={StaticResource source}}">
        </ig:RingSeries>
    </ig:XamDoughnutChart.Series>
</ig:XamDoughnutChart>

항목에 대한 데이터 원본은 다음과 같이 페이지의 cs 파일에 생성됩니다.

public class Category
{
     public string Label { get; set; }
     public double productionShare { get; set; }
}
 
public class HierarchalDataCollection : List<Category>
{
     public HierarchalDataCollection()
     {
         this.Add(new Category { Label = "Footwear", productionShare = 46 });
         this.Add(new Category { Label = "Clothing", productionShare = 38 });
         this.Add(new Category { Label = "Accessories", productionShare = 16 });
     }
}

 

Basic XAML doughnut chart

기본적으로 도넛 차트 만드는 단계입니다. 물론 범례, 브러시, 슬라이스 선택 및 슬라이스 폭발과 같은 많은 옵션이 있어 차트를 더욱 매력적으로 만들 수 있습니다. 설명서에서 찾을 수 있는 옵션에 대한 자세한 내용. 특정 옵션을 추가하는 방법에 대한 힌트를 드리겠습니다. 예를 들어, 조각을 선택하여 쪼개고 스타일을 변경하려면 AllowSliceExplosionAllowSliceSelection 옵션을 추가하고 해당 값을 true로 설정합니다. 그런 다음 다음과 같이 슬라이스 클릭 이벤트를 만듭니다.

XAML:

AllowSliceExplosion="True"
AllowSliceSelection="True"
SliceClick="slice_SliceClick"

C#:

private void slice_SliceClick(object sender, Infragistics.Controls.Charts.SliceClickEventArgs e)
{
    e.IsSelected = !e.IsSelected;
    e.IsExploded = !e.IsExploded;
}

 

Exploded XAML doughnut chart

사용자 지정 계층적 차트

계층적 데이터를 시각화해야 하는 경우 차트의 다중 링 시각화를 사용할 수 있습니다. 우리는 세 개의 반지 도넛 차트를 만들 것입니다.이 차트는 주요 범주를 하위 범주로 분류하여 표시합니다.  이를 위해 세 개의 시리즈를 만들고 다음과 같이 데이터 소스를 정의할 것입니다.

XAML :

<ig:XamDoughnutChart.Series>
    <ig:RingSeries 
	StartAngle="30"
        LabelMemberPath="Label"
        ValueMemberPath="productionShare"
        LabelsPosition="BestFit"
        ItemsSource="{Binding Mode=OneWay, Source={StaticResource source}}"
        Loaded="RingSeries_Loaded">
    </ig:RingSeries>
    <ig:RingSeries
        StartAngle="30"
        LabelMemberPath="Label"
        ValueMemberPath="productionShare"
        LabelsPosition="BestFit"
        Loaded="RingSeries_Loaded"
        OthersCategoryThreshold="0" >
    </ig:RingSeries>
    <ig:RingSeries
        StartAngle="30"
        LabelMemberPath="Label"
        ValueMemberPath="productionShare"
        LabelsPosition="BestFit"
        OthersCategoryThreshold="0">
    </ig:RingSeries>
</ig:XamDoughnutChart.Series>

C# :

public class HierarchalDataCollection : List<Category>
    {
        public HierarchalDataCollection()
        {
            
            this.Add(new Category { Label = "Footwear"});
            this.Add(new Category { Label = "Clothing"});
            this.Add(new Category { Label = "Accessories"});
            this.Add(new Category { Label = "Tech" });
 
            
            this[0].Children.Add(new Category { Label = "Boots" });
            this[0].Children.Add(new Category { Label = "Shoes" });
            this[0].Children.Add(new Category { Label = "Sneakers" });
            this[0].Children.Add(new Category { Label = "Slippers" });
 
            this[1].Children.Add(new Category { Label = "Dresses" });
            this[1].Children.Add(new Category { Label = "T-shirts" });
            this[1].Children.Add(new Category { Label = "Shirts" });
            this[1].Children.Add(new Category { Label = "Pants" });
 
            this[2].Children.Add(new Category { Label = "Bag" });
            this[2].Children.Add(new Category { Label = "Jewelry" });
            this[2].Children.Add(new Category { Label = "Scarf" });
 
            this[3].Children.Add(new Category { Label = "PC"});
            this[3].Children.Add(new Category { Label = "Laptops"});
            this[3].Children.Add(new Category { Label = "Tablets"});
            this[3].Children.Add(new Category { Label = "Phones"});
 
            
            this[0].Children[0].Children.Add(new Category { Label = "B1", productionShare = 3 });
            this[0].Children[0].Children.Add(new Category { Label = "B3", productionShare = 3 });
            this[0].Children[0].Children.Add(new Category { Label = "B4", productionShare = 4 });
 
            this[0].Children[1].Children.Add(new Category { Label = "S1", productionShare = 3 });
            this[0].Children[1].Children.Add(new Category { Label = "S2", productionShare = 5 });
            this[0].Children[1].Children.Add(new Category { Label = "S3", productionShare = 4 });
 
            this[0].Children[2].Children.Add(new Category { Label = "Sn1", productionShare = 6 });
            this[0].Children[2].Children.Add(new Category { Label = "Sn2", productionShare = 9 });
 
            this[0].Children[3].Children.Add(new Category { Label = "SL1", productionShare = 2 });
            this[0].Children[3].Children.Add(new Category { Label = "Sl2", productionShare = 4 });
            this[0].Children[3].Children.Add(new Category { Label = "Sl3", productionShare = 3 });
 
           
            this[1].Children[0].Children.Add(new Category { Label = "d1", productionShare = 3 });
            this[1].Children[0].Children.Add(new Category { Label = "d2", productionShare = 3 });
            this[1].Children[0].Children.Add(new Category { Label = "d3", productionShare = 2 });
 
            this[1].Children[1].Children.Add(new Category { Label = "t1", productionShare = 5 });
            this[1].Children[1].Children.Add(new Category { Label = "t2", productionShare = 4 });
            this[1].Children[1].Children.Add(new Category { Label = "t3", productionShare = 2 });
            this[1].Children[1].Children.Add(new Category { Label = "t4", productionShare = 1 });
 
            this[1].Children[2].Children.Add(new Category { Label = "sh1", productionShare = 3 });
            this[1].Children[2].Children.Add(new Category { Label = "sh2", productionShare = 3 });
            this[1].Children[2].Children.Add(new Category { Label = "sh3", productionShare = 2 });
 
            this[1].Children[3].Children.Add(new Category { Label = "p1", productionShare = 4 });
            this[1].Children[3].Children.Add(new Category { Label = "p2", productionShare = 6 });
 
            
            this[2].Children[0].Children.Add(new Category { Label = "bag1", productionShare = 2 });
            this[2].Children[0].Children.Add(new Category { Label = "bag2", productionShare = 1 });
            this[2].Children[0].Children.Add(new Category { Label = "bag3", productionShare = 4 });
 
            this[2].Children[1].Children.Add(new Category { Label = "j1", productionShare = 3 });
            this[2].Children[1].Children.Add(new Category { Label = "j2", productionShare = 2 });
 
            this[2].Children[2].Children.Add(new Category { Label = "sc1", productionShare = 1 });
            this[2].Children[2].Children.Add(new Category { Label = "sc2", productionShare = 1 });
            this[2].Children[2].Children.Add(new Category { Label = "sc3", productionShare = 1 });
            this[2].Children[2].Children.Add(new Category { Label = "sc4", productionShare = 1 });
 
            
            this[3].Children[0].Children.Add(new Category { Label = "pc1", productionShare = 3 });
            this[3].Children[0].Children.Add(new Category { Label = "pc2", productionShare = 2 });
            this[3].Children[0].Children.Add(new Category { Label = "pc3", productionShare = 5 });
 
            this[3].Children[1].Children.Add(new Category { Label = "l1", productionShare = 4 });
            this[3].Children[1].Children.Add(new Category { Label = "l2", productionShare = 3 });
 
            this[3].Children[2].Children.Add(new Category { Label = "tab1", productionShare = 4 });
            this[3].Children[2].Children.Add(new Category { Label = "tab2", productionShare = 3 });
            this[3].Children[2].Children.Add(new Category { Label = "tab3", productionShare = 3 });
            this[3].Children[2].Children.Add(new Category { Label = "tab4", productionShare = 3 });
 
            this[3].Children[3].Children.Add(new Category { Label = "ph1", productionShare = 2 });
            this[3].Children[3].Children.Add(new Category { Label = "ph2", productionShare = 3 });
            this[3].Children[3].Children.Add(new Category { Label = "ph3", productionShare = 2 });
            this[3].Children[3].Children.Add(new Category { Label = "ph4", productionShare = 1 });
        }
    }

이제 시각화하려는 모든 데이터가 준비되었습니다. 우리가 계층적으로 보이게 하기 때문에 모든 범주에 대한 다른 슬라이스가 비슷한 색상을 갖는다면 좋을 것입니다. 우리가 할 일은 가장 안쪽 링에서 기본 브러시를 가져와 모든 단계에서 가볍게 만드는 것입니다. 다음 코드에서는 먼저 반지에 몇 명의 자식이 있는지 파악한 다음 자식과 완벽하게 일치하는 브러시 컬렉션을 만드는 것을 볼 수 있습니다.

private void RingSeries_Loaded(object sender, RoutedEventArgs e)
{
    var ringSeries = (sender as RingSeries);
    var count = ringSeries.Ring.ArcItems[0].SliceItems.Count();
    var brushes = ringSeries.Brushes;
    BrushCollection brushesMatch = new BrushCollection();
 
    for (var i = 0; i < count; i++)
    {
        var childrenCount = (ringSeries.ItemsSource as List<Category>)[i].Children.Count();
        var child = (ringSeries.ItemsSource as List<Category>)[i].Children;
 
        var brush = brushes[i];
 
        for (var j = 0; j < childrenCount; j++)
        {
            double step = 1 / (double)childrenCount;
            Random rand = new Random();
                double val = (1 + j) * step - .3;
 
                brushesMatch.Add(brush.GetLightened(val));
        }
    }
 
    ringSeries.Chart.Series[ringSeries.Ring.Index + 1].Brushes = brushesMatch;
}

 

Custom Hierarchial Doughnut Chart

표시하려는 데이터에 따라 자식의 색상 방식을 변경할 수 있습니다(예: 임의의 색조로 브러시할 수 있음). 어떤 종류의 브러시를 사용하든 - Solid, Radial 또는 Linear Gradient GetLightend 확장 메소드가 처리합니다.

private void RingSeries_Loaded(object sender, RoutedEventArgs e)
{
    var ringSeries = (sender as RingSeries);
    var count = ringSeries.Ring.ArcItems[0].SliceItems.Count();
    var brushes = ringSeries.Brushes;
    BrushCollection brushesMatch = new BrushCollection();
 
    for (var i = 0; i < count; i++)
    {
        var childrenCount = (ringSeries.ItemsSource as List<Category>)[i].Children.Count();
        var child = (ringSeries.ItemsSource as List<Category>)[i].Children;
 
        var brush = brushes[i];
 
        for (var j = 0; j < childrenCount; j++)
        {
            Random rand = new Random();
 
            if (j % 2 == 0)
            {
                double val = Math.Round((rand.NextDouble() / 4), 2);
                brushesMatch.Add(brush.GetLightened(-val));
            }
            else
            {
                double val = Math.Round((rand.NextDouble() / 3), 2) + 0.2;
                brushesMatch.Add(brush.GetLightened(val));
            }
        }
    }
 
    ringSeries.Chart.Series[ringSeries.Ring.Index + 1].Brushes = brushesMatch;
}
Random lighten hierarchical doughnut chart

도넛 차트에 대해 자세히 알아보려면 제품 페이지를 확인하세요.

A WPF sample and Silverlight sample.

Twitter에서 팔로우할 수 있습니다.@ Infragistics그리고 계속 연락하세요페이스북,구글+그리고링크드인!

데모 요청