How to put legend over chart, positioned at top center and top right?

I know that setting DockPosition to Floating places the legend absolutely, defaulting to top left, but I want to know how to position it without having to manually put in values for the OffsetX and OffSetY.

9 Replies

MP Michael Prabhu M Syncfusion Team August 7, 2018 10:57 AM UTC

Hi Peter, 
Greetings from Syncfusion, we have analyzed your requirement and it can be achieved as a workaround by using CustomChartRenderer for all platforms. Please refer below code snippet. 
  
Code snippet for Android [CustomChartRenderer.CS]:    
  
public class CustomNativeChart : SfChartExt 
    { 
  
        public CustomNativeChart(Android.Content.Context context) : base(context) 
        { 
  
        } 
  
        protected override void OnLayout(bool changed, int left, int top, int right, int bottom) 
        { 
            base.OnLayout(changed, left, top, right, bottom); 
  
            if (Legend != null) 
            { 
                PropertyInfo property = typeof(Native.SfChart).GetProperty("ChartLegendlayout", BindingFlags.NonPublic | BindingFlags.Instance); 
                var legendLayout = (Native.ChartLegendLayout)property.GetValue(this, null); 
                var legendWidth = legendLayout.Width; 
                legendLayout.SetX(this.Width - legendWidth); 
                legendLayout.SetY(legendLayout.Height); 
            } 
        } 
    } 
 
  
Code snippet for iOS and macOS [CustomChartRenderer.CS]:    
  
public class CustomNativeChart : Native.SFChart 
    { 
        public CustomNativeChart() 
        { 
  
        } 
  
        public override void LayoutSubviews() 
        { 
            base.LayoutSubviews(); 
  
            if (this.Legend != null) 
            { 
  
                PropertyInfo property = typeof(Native.SFChart).GetProperty("LegendView", BindingFlags.NonPublic | BindingFlags.Instance); 
                //Convert the LegendView as NsView for macOS 
                var legendView = (UIView)property.GetValue(this, null); 
  
                if (legendView.Frame.Width > 0) 
                { 
                    legendView.Frame = new CGRect(this.Frame.Width - legendView.Frame.Width, legendView.Frame.Height, legendView.Frame.Width, legendView.Frame.Height); 
                    legendView.SetNeedsLayout(); 
                    legendView.SetNeedsDisplay(); 
                    property.SetValue(this, legendView); 
                } 
            } 
  
        } 
 
  
Code snippet for UWP [CustomChartRenderer.CS]:    
  
public class CustomChartRenderer : SfChartRenderer 
    { 
        Native.SfChart nativechart; 
        protected override void OnElementChanged(ElementChangedEventArgs<SfChart> e) 
        { 
            base.OnElementChanged(e); 
  
            nativechart = Control; 
        } 
  
        protected override Size ArrangeOverride(Size finalSize) 
        { 
            if (this.nativechart.Legend != null) 
            { 
                    var legend = nativechart.Legend as Native.ChartLegend; 
                    PropertyInfo property = typeof(Native.ChartLegend).GetProperty("ArrangeRect", BindingFlags.NonPublic | BindingFlags.Instance); 
                    var legendLayout = (Windows.Foundation.Rect)property.GetValue(nativechart.Legend, null); 
                    legendLayout = new Windows.Foundation.Rect(nativechart.DesiredSize.Width - legend.DesiredSize.Width,legend.DesiredSize.Height,legend.DesiredSize.Width,legend.DesiredSize.Height); 
                    property.SetValue(nativechart.Legend, legendLayout); 
            } 
  
            return base.ArrangeOverride(finalSize); 
        } 
  
    } 
 
  
Based on this we have also prepared a sample and it can be downloaded from the link below. 
Sample: 139088
 
 
Sample Screenshot: 
 
 
Thanks, 
Michael 
 



PC Peter Cardenas August 8, 2018 07:15 PM UTC

I get an error that says Value cannot be null, Parameter name key in the xaml file that I am using. I already made sure that the namespace and assembly name were correct, and I don't know what else could be causing it.



MP Michael Prabhu M Syncfusion Team August 9, 2018 11:22 AM UTC

Hi Peter, 
 
The sample provided by us is working properly at our end, are you having trouble running our sample? Can you provide us any screenshot or stack trace of the sample? Also, now we have attached a sample below with all the NuGet properly added can you check this sample below? 
 
Sample: 139088_n
 
 
Thanks, 
Michael 




PC Peter Cardenas August 9, 2018 10:35 PM UTC

Ok so it works on the sample, and there were no bugs in my main project (I accidentally added a closing bracket), but the legend is not showing. The data of the chart, including the plot points for the lines and the legend titles, are created dynamically, so is there some method I need to call after all the data is added?


MP Michael Prabhu M Syncfusion Team August 10, 2018 12:49 PM UTC

Hi Peter, 
 
The dynamic update of legend was not happening only in the UWP platform and we have achieved in uwp with Control_SeriesBoundsChanged event. 
Please refer below code snippet. 
Code snippet for Android [CustomChartRenderer.CS]:    
public class CustomNativeChart : SfChartExt 
    { 
        public CustomNativeChart(Android.Content.Context context) : base(context) 
        { 
        } 
        protected override void OnLayout(bool changed, int left, int top, int right, int bottom) 
        { 
            base.OnLayout(changed, left, top, right, bottom); 
            if (Legend != null) 
            { 
PropertyInfo property = typeof(Native.SfChart).GetProperty("ChartLegendlayout", BindingFlags.NonPublic | BindingFlags.Instance); 
                var legendLayout = (Native.ChartLegendLayout)property.GetValue(this, null); 
                var legendWidth = legendLayout.Width; 
                Legend.DockPosition = Native.ChartDock.Floating; 
                Legend.OffsetX = this.Width - legendWidth; 
                Legend.OffsetY = 0;            
       } 
        } 
    } 
 
Code snippet for iOS and macOS [CustomChartRenderer.CS]:    
public class CustomNativeChart : Native.SFChart 
    { 
        public CustomNativeChart() 
        { 
        } 
        public override void LayoutSubviews() 
        { 
            base.LayoutSubviews(); 
            if (this.Legend != null) 
            { 
                PropertyInfo property = typeof(Native.SFChart).GetProperty("LegendView", BindingFlags.NonPublic | BindingFlags.Instance); 
                //Convert the LegendView as NsView for macOS 
                var legendView = (UIView)property.GetValue(this, null); 
                if (legendView.Frame.Width > 0) 
                { 
                    legendView.Frame = new CGRect(this.Frame.Width - legendView.Frame.Width, legendView.Frame.Height, legendView.Frame.Width, legendView.Frame.Height); 
                    legendView.SetNeedsLayout(); 
                    legendView.SetNeedsDisplay(); 
                    property.SetValue(this, legendView); 
                } 
            } 
        } 
 
Code snippet for UWP [CustomChartRenderer.CS]:    
public class CustomChartRenderer : SfChartRenderer 
    { 
        Native.SfChart nativechart; 
        protected override void OnElementChanged(ElementChangedEventArgs<SfChart> e) 
        { 
            base.OnElementChanged(e); 
            nativechart = Control; 
        } 
        protected override Size ArrangeOverride(Size finalSize) 
        { 
            if (this.nativechart.Legend != null) 
            { 
                    var legend = nativechart.Legend as Native.ChartLegend; 
                    PropertyInfo property = typeof(Native.ChartLegend).GetProperty("ArrangeRect", BindingFlags.NonPublic | BindingFlags.Instance); 
                    var legendLayout = (Windows.Foundation.Rect)property.GetValue(nativechart.Legend, null); 
                    legendLayout = new Windows.Foundation.Rect(nativechart.DesiredSize.Width - legend.DesiredSize.Width,legend.DesiredSize.Height,legend.DesiredSize.Width,legend.DesiredSize.Height); 
                    property.SetValue(nativechart.Legend, legendLayout); 
            } 
            return base.ArrangeOverride(finalSize); 
        } 
private void Control_SeriesBoundsChanged(object sender, Native.ChartSeriesBoundsEventArgs e) 
        { 
            var nativeChart = sender as Native.SfChart; 
            if (nativeChart.Legend != null) 
            { 
                var legend = nativeChart.Legend as Native.ChartLegend; 
                legend.DockPosition = Native.ChartDock.Floating; 
                legend.OffsetX = (DesiredSize.Width - legend.DesiredSize.Width); 
                legend.OffsetY = 0; 
                
            } 
        } 
    } 
 
 
Please find the sample we prepared from the following location. 
 
Sample:139088
 
 
Also, now the dynamic update will work in all platforms. 
 
Thanks, 
Michael 



PC Peter Cardenas August 12, 2018 11:12 AM UTC

Alright I got it to work, for some reason, the legend was never created even though I thought it was in the xaml, so I added it in the code. I have another question: how would I stack the series labels vertically?


MP Michael Prabhu M Syncfusion Team August 13, 2018 11:41 AM UTC

Hi Peter,  
 
You could stack the legend series label vertically by setting the Orientation property to Vertical in Chart legend, you can refer more on this from the below link. 
 
 
Hope this helps. 
 
Thanks, 
Michael 




PC Peter Cardenas August 14, 2018 01:20 AM UTC

Thank you so much! It's working now, but I'll let you know of any further issues that I encounter.


MP Michael Prabhu M Syncfusion Team August 14, 2018 06:43 AM UTC

Hi Peter, 
 
Thanks for the update, we are glad that you have achieved your requirement, feel free to contact us any time if you require any other assistance from us. We are happy to help you.  
 
Thanks, 
Michael 



Loader.
Up arrow icon