Your Privacy Matters: We use our own and third-party cookies to improve your experience on our website. By continuing to use the website we understand that you accept their use. Cookie Policy
105
Scale break feature
posted

Any plans to implement this feature?

Any suggestions what to do with such a charts?

In our web-app we are using DX chart and this GREAT feature http://community.devexpress.com/blogs/ctodx/archive/2009/06/23/sneak-peek-scale-breaks-in-winforms-and-web-charts.aspx

Your controls are great, but scale break feature is must have for financial data.

Parents Reply
  • 30692
    Suggested Answer
    Offline posted in reply to Gabriele

    Grabiele,

    You can find the public roadmap here: https://es.infragistics.com/products/all

    You might be interested to know that with a bit work you can implement a version of y scale breaks on the current version of the xamDataChart. I'll provide a sample below:

    Xaml:

    <UserControl.Resources>
            <local:TestData x:Key="data" />
        </UserControl.Resources>
    
        <Grid x:Name="LayoutRoot" Background="White">
            <local:XamDataChartWithYBreaks>
                <local:XamDataChartWithYBreaks.Breaks>
                    <local:Range Start="10" End="490" />
                </local:XamDataChartWithYBreaks.Breaks>
                
                <local:XamDataChartWithYBreaks.ChartTemplate>
                    <DataTemplate>
                        <igChart:XamDataChart x:Name="chart" HorizontalAlignment="Stretch">
                            <igChart:XamDataChart.Axes>
                                <igChart:CategoryXAxis x:Name="xAxis" 
                                                       ItemsSource="{StaticResource data}" 
                                                       Label="{}{Label}" />
                                <igChart:NumericYAxis x:Name="yAxis" />
                            </igChart:XamDataChart.Axes>
                            <igChart:XamDataChart.Series>
                                <igChart:ColumnSeries x:Name="column"
                                                      ItemsSource="{StaticResource data}"
                                                      XAxis="{Binding ElementName=xAxis}"
                                                      YAxis="{Binding ElementName=yAxis}"
                                                      ValueMemberPath="Value" />
                            </igChart:XamDataChart.Series>
                        </igChart:XamDataChart>
                    </DataTemplate>
                </local:XamDataChartWithYBreaks.ChartTemplate>
            </local:XamDataChartWithYBreaks>
        </Grid>
    

     

    And Code behind:

     public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
            }
        }
    
        public class TestDataItem
        {
            public string Label { get; set; }
            public double Value { get; set; }
        }
    
        public class TestData
            : ObservableCollection<TestDataItem>
        {
            private static Random _rand = new Random();
            public TestData()
            {
                Add(new TestDataItem() { Label = "A", Value = 1 });
                Add(new TestDataItem() { Label = "B", Value = 4 });
                Add(new TestDataItem() { Label = "C", Value = 491 });
                Add(new TestDataItem() { Label = "D", Value = 500 });
                Add(new TestDataItem() { Label = "E", Value = 5 });
                Add(new TestDataItem() { Label = "F", Value = 3 });
            }
        }
    
        public class JaggedBreach
            : ContentControl
        {
            private Polyline _path = new Polyline();
            private static Random _rand = new Random();
            public JaggedBreach()
            {
                List<Point> pointsBelow = new List<Point>();
                List<Point> pointsAbove = new List<Point>();
                double currY = 5.0;
                for (int i = 0; i < 80; i++)
                {
                    double x = 1.0 * (i / 80.0);
                    if (_rand.NextDouble() > .5)
                    {
                        currY += _rand.NextDouble();
                    }
                    else
                    {
                        currY -= _rand.NextDouble();
                    }
                    if (currY < 0)
                    {
                        currY = 0;
                    }
                    if (currY > 10)
                    {
                        currY = 10;
                    }
                    double y = currY;
                    pointsBelow.Add(new Point()
                    {
                        X = x,
                        Y = y
                    });
                    pointsAbove.Add(new Point()
                    {
                        X = x,
                        Y = 10 + y
                    });
                }
                _path.Stretch = Stretch.Fill;
    
                var brush = new LinearGradientBrush();
                brush.GradientStops.Add(new GradientStop()
                {
                    Color = Colors.LightGray
                });
                brush.GradientStops.Add(new GradientStop()
                {
                    Color = Colors.Gray,
                    Offset = 1
                });
    
                _path.Fill = brush;
                _path.StrokeThickness = .5;
                _path.Stroke = new SolidColorBrush(Colors.DarkGray);
    
                this.HorizontalContentAlignment = 
                    HorizontalAlignment.Stretch;
                this.VerticalContentAlignment = 
                    VerticalAlignment.Stretch;
                this.Height = 25;
                this.Content = _path;
    
                foreach (var point in pointsAbove)
                {
                    _path.Points.Add(point);
                }
                pointsBelow.Reverse();
                foreach (var point in pointsBelow)
                {
                    _path.Points.Add(point);
                }
                _path.Points.Add(pointsAbove.First());
            }
    
        }
    
        public class XamDataChartWithYBreaks
            : ContentControl
        {
            private StackPanel _content = new StackPanel();
    
            public XamDataChartWithYBreaks()
            {
                _breaks = new BreakCollection();
                _breaks.CollectionChanged += 
                    Breaks_CollectionChanged;
    
                this.HorizontalContentAlignment = 
                    HorizontalAlignment.Stretch;
                this.VerticalContentAlignment = 
                    VerticalAlignment.Stretch;
                this.Content = _content;
                this.SizeChanged += 
                    XamDataChartWithYBreaks_SizeChanged;
            }
    
            void XamDataChartWithYBreaks_SizeChanged(
                object sender, 
                SizeChangedEventArgs e)
            {
                UpdateChartHeights();
            }
    
            void Breaks_CollectionChanged(
                object sender,
                NotifyCollectionChangedEventArgs e)
            {
                UpdateContent();
            }
    
            private DataTemplate _chartTemplate;
            public DataTemplate ChartTemplate
            {
                get { return _chartTemplate; }
                set
                {
                    _chartTemplate = value;
                    UpdateContent();
                }
            }
    
            private BreakCollection _breaks;
            public BreakCollection Breaks { get { return _breaks; } }
            private Guid _syncChannel = Guid.NewGuid();
    
            private void UpdateContent()
            {
                if (ChartTemplate == null)
                {
                    return;
                }
    
                foreach (XamDataChart chart in
                    _content.Children.OfType<XamDataChart>())
                {
                    NumericYAxis yAxis = GetYAxis(chart);
                    if (yAxis != null)
                    {
                        yAxis.RangeChanged -= yAxis_RangeChanged;
                    }
                }
    
                _content.Children.Clear();
    
                var ranges = GetRanges();
                XamDataChart last = null;
                foreach (var range in ranges.Reverse())
                {
                    XamDataChart chart = GetChartForRange(range);
                    if (chart == null)
                    {
                        continue;
                    }
                    last = chart;
                    if (_content.Children.Count > 0)
                    {
                        _content.Children.Add(new JaggedBreach());
                    }
                    _content.Children.Add(chart);
                }
    
                if (last != null)
                {
                    CategoryAxisBase xAxis = GetXAxis(last);
                    xAxis.LabelSettings.Visibility = Visibility.Visible;
                }
            }
    
            private XamDataChart GetChartForRange(Range range)
            {
                XamDataChart chart = ChartTemplate.LoadContent() as XamDataChart;
                if (chart == null)
                {
                    return null;
                }
    
                NumericYAxis yAxis = GetYAxis(chart);
                if (yAxis == null)
                {
                    return null;
                }
                yAxis.RangeChanged += yAxis_RangeChanged;
    
                if (range.Start != double.MinValue)
                {
                    yAxis.MinimumValue = range.Start;
                }
                if (range.End != double.MaxValue)
                {
                    yAxis.MaximumValue = range.End;
                }
                yAxis.LabelSettings.Extent = 50;
                chart.VerticalZoomable = false;
                chart.VerticalZoombarVisibility = Visibility.Collapsed;
                chart.HorizontalZoombarVisibility = Visibility.Collapsed;
                chart.HorizontalZoomable = true;
    
                CategoryAxisBase xAxis = GetXAxis(chart);
                if (xAxis == null)
                {
                    return null;
                }
                xAxis.LabelSettings.Visibility = Visibility.Collapsed;
    
                SyncManager.SetSyncSettings(chart,
                    new SyncSettings()
                    {
                        SyncChannel = _syncChannel.ToString(),
                        SynchronizeHorizontally = true,
                        SynchronizeVertically = false
                    });
    
                return chart;
            }
    
            void yAxis_RangeChanged(
                object sender, 
                AxisRangeChangedEventArgs e)
            {
                UpdateChartHeights();
            }
    
            private void UpdateChartHeights()
            {
                double totalRange = 0.0;
                int count = 0;
                foreach (XamDataChart chart in
                    _content.Children.OfType<XamDataChart>())
                {
                    var yAxis = GetYAxis(chart);
                    totalRange += 
                        yAxis.ActualMaximumValue - yAxis.ActualMinimumValue;
                    count++;
                }
    
                double unusable = 0.0;
                if (count > 1)
                {
                    unusable = (count - 1) * 25.0;
                }
    
                foreach (XamDataChart chart in
                    _content.Children.OfType<XamDataChart>())
                {
                    var yAxis = GetYAxis(chart);
                    double percentRange =
                        (yAxis.ActualMaximumValue - yAxis.ActualMinimumValue)
                        / totalRange;
                    chart.Height = 
                        (this.ActualHeight - unusable) * percentRange;
                }
            }
    
            private CategoryAxisBase GetXAxis(XamDataChart chart)
            {
                return chart.Axes.OfType<CategoryAxisBase>().FirstOrDefault();
            }
    
            private NumericYAxis GetYAxis(XamDataChart chart)
            {
                return chart.Axes.OfType<NumericYAxis>().FirstOrDefault();
            }
    
            private IEnumerable<Range> GetRanges()
            {
                if (Breaks.Count < 1)
                {
                    yield return new Range()
                    {
                        Start = double.MinValue,
                        End = double.MaxValue
                    };
                    yield break;
                }
                yield return new Range()
                {
                    Start = double.MinValue,
                    End = Breaks.First().Start
                };
                for (int i = 0; i < Breaks.Count; i++)
                {
                    if (i + 1 < Breaks.Count)
                    {
                        yield return new Range()
                        {
                            Start = Breaks[i].End,
                            End = Breaks[i + 1].Start
                        };
                    }
                    else
                    {
                        yield return new Range()
                        {
                            Start = Breaks[i].End,
                            End = double.MaxValue
                        };
                    }
                }
            }
        }
    
        public class BreakCollection
            : ObservableCollection<Range>
        {
    
        }
    
        public class Range
            : DependencyObject
        {
            public static readonly DependencyProperty StartProperty =
                DependencyProperty.Register(
                "Start",
                typeof(double),
                typeof(Range),
                new PropertyMetadata(0.0));
    
            public double Start
            {
                get
                {
                    return (double)(GetValue(StartProperty));
                }
                set
                {
                    SetValue(StartProperty, value);
                }
            }
    
            public static readonly DependencyProperty EndProperty =
               DependencyProperty.Register(
               "End",
               typeof(double),
               typeof(Range),
               new PropertyMetadata(0.0));
    
            public double End
            {
                get
                {
                    return (double)(GetValue(EndProperty));
                }
                set
                {
                    SetValue(EndProperty, value);
                }
            }
        }
    

    Pretty neat, huh? Hope this helps!

    -Graham

Children