Hello,
I have 2 issues with the attached chart legend:
1) I would like the legend items to be displayed on 2 adjacent columns (see chart legend expected.png). Is that possible?
2) I don't know if you noticed but item legend texts are not perfectly left aligned. Do you have a fix for that?
Best,
Mathias
18 Answers, 1 is accepted
Thank you for writing.
The ChartLegendElement displays the legend items in a StackLayoutElement which can be vertical or horizontal. In order to display the legend items in two columns, you can use two additional vertical StackLayoutElement. Here is a sample code snippet, which result is illustrated on the attached screenshot:
public
Form1()
{
InitializeComponent();
Random rand =
new
Random();
StringBuilder sb =
new
StringBuilder();
for
(
int
i = 0; i < 8; i++)
{
LineSeries lineSeries =
new
LineSeries();
sb =
new
StringBuilder();
for
(
int
j = 0; j < i + 1; j++)
{
sb.Append(
"S0"
+ i);
}
lineSeries.LegendTitle = sb.ToString();
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Jan"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Apr"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Jul"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Oct"
));
this
.radChartView1.Series.Add(lineSeries);
}
this
.radChartView1.ShowLegend =
true
;
this
.radChartView1.ChartElement.LegendPosition = LegendPosition.Bottom;
}
class
MyChart : RadChartView
{
protected
override
RadChartElement CreateChartElement()
{
return
new
MyChartElement();
}
}
class
MyChartElement : RadChartElement
{
protected
override
ChartLegendElement CreateChartLegendElement()
{
return
new
MyLegendElement(
this
);
}
protected
override
Type ThemeEffectiveType
{
get
{
return
typeof
(RadChartElement);
}
}
}
class
MyLegendElement : ChartLegendElement
{
StackLayoutElement leftPanel =
new
StackLayoutElement();
StackLayoutElement rightPanel =
new
StackLayoutElement();
public
MyLegendElement(RadChartElement chartElement) :
base
(chartElement)
{
}
protected
override
void
CreateChildElements()
{
base
.CreateChildElements();
this
.StackElement.Orientation = System.Windows.Forms.Orientation.Horizontal;
}
protected
override
void
OnLegendInfosCollectionChanged(Telerik.WinControls.Data.NotifyCollectionChangedEventArgs e,
bool
providerChange)
{
if
(!
this
.StackElement.Children.Contains(leftPanel))
{
this
.StackElement.Children.Add(leftPanel);
leftPanel.Orientation = System.Windows.Forms.Orientation.Vertical;
}
if
(!
this
.StackElement.Children.Contains(rightPanel))
{
this
.StackElement.Children.Add(rightPanel);
rightPanel.Orientation = System.Windows.Forms.Orientation.Vertical;
}
leftPanel.Children.Clear();
rightPanel.Children.Clear();
for
(
int
i = 0; i <
this
.Provider.LegendInfos.Count; i++)
{
LegendItemElement element =
this
.OnVisualItemCreating(
this
.Provider.LegendInfos[i]);
if
(i <
this
.Provider.LegendInfos.Count / 2)
{
leftPanel.Children.Add(element);
}
else
{
rightPanel.Children.Add(element);
}
}
}
protected
override
Type ThemeEffectiveType
{
get
{
return
typeof
(ChartLegendElement);
}
}
}
As to the question about text alignment of the items in the LegendElement, I was unable to reproduce it on my end with the specified version 2015.1 331. I have attached my sample project. Could you please have a look into it and specify how it differs from your real setup? Thus, we would be able to investigate the precise case and assist you further. Thank you in advance.
I am looking forward to your reply.
Dess
Telerik
See What's Next in App Development. Register for TelerikNEXT.
BUEN DÍA ESTOY REALIZANDO UNAS GRAFICAS, TENGO UNA DUDA, CON EL TIPO DE SERIE TYPE Line LA LEGENDA SE VISUALIZA, PERO CON EL TYPE ScatterLine LA S LEYENDAS NO SE VISUALIZAN, E VISTO EL docs.telerik Y LOS EJEMPLOS MOSTRADOS NO TIENEN VISUALIZADOS LA LEYENDA, ¿HAY ALGUNA FORMA QUE SE VISUALICEN?
ADJUNTO MI PANTALLA
Thank you for writing back.
I would like to note that the official language for communication in the Telerik forums is English. If you have any questions related to the Telerik UI for WinForms product, feel free to use the appropriate language and the community will gladly assist you.
Thank you for your understanding.
Regards,
Dess
Progress Telerik
Hello,
I am creating stacked bar series using Telerik Win forms in my server side in Vb. I am not able to display legends at the bottom in multiple lines. I am attaching both actual and expended chart.
Since Q1 2015 when there are many items in the chart legend a scroll bar will appear so users can scroll through the items. The legend items are not wrapped indeed
I have prepared a sample code snippet which achieves a similar custom scenario. The obtained result is illustrated in the below screenshot:
Sub New()
InitializeComponent()
Dim rand As New Random
Dim list As New List(Of LineSeries)
For index = 1 To 15
Dim ls As New LineSeries
ls.LegendTitle =
"Series "
& index
list.Add(ls)
Next
For index = 1 To 100
For Each s As LineSeries In list
s.DataPoints.Add(New CategoricalDataPoint(index, rand.Next(0, rand.Next(5, 20))))
Next
Next
Me.RadChartView1.Series.AddRange(list.ToArray())
Me.RadChartView1.ShowLegend = True
Me.RadChartView1.ChartElement.LegendPosition = LegendPosition.Bottom
End Sub
Friend Class MyChart
Inherits RadChartView
Protected Overrides Function CreateChartElement() As RadChartElement
Return New MyChartElement()
End Function
End Class
Friend Class MyChartElement
Inherits RadChartElement
Protected Overrides Function CreateChartLegendElement() As ChartLegendElement
Return New MyLegendElement(Me)
End Function
Protected Overrides ReadOnly Property ThemeEffectiveType() As Type
Get
Return GetType(RadChartElement)
End Get
End Property
End Class
Friend Class MyLegendElement
Inherits ChartLegendElement
Private panel As RadListViewElement
Public Sub New(chartElement As RadChartElement)
MyBase.New(chartElement)
End Sub
Protected Overrides Sub OnLegendInfosCollectionChanged(e As Telerik.WinControls.Data.NotifyCollectionChangedEventArgs, providerChange As Boolean)
MyBase.OnLegendInfosCollectionChanged(e, providerChange)
If e.Action = Telerik.WinControls.Data.NotifyCollectionChangedAction.Add Then
Dim li As LegendItem = TryCast(e.NewItems(0), LegendItem)
panel.Items.Add(li.Title)
End If
End Sub
Protected Overrides Sub CreateChildElements()
MyBase.CreateChildElements()
panel = New RadListViewElement()
panel.StretchHorizontally = True
panel.StretchVertically = False
panel.ViewType = ListViewType.IconsView
panel.ItemSize = New Drawing.Size(100, 20)
panel.ShouldHandleMouseInput = True
panel.NotifyParentOnMouseInput = False
panel.MaxSize = New Drawing.Size(500, 100)
Me.StackElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed
Me.Children.Add(panel)
End Sub
Protected Overrides ReadOnly Property ThemeEffectiveType() As Type
Get
Return GetType(ChartLegendElement)
End Get
End Property
End Class
Note that this is just a sample approach and it may not handle all possible cases. Feel free to modify it in a way which suits your requirement best.
I hope this information helps. If you have any additional questions, please let me know.
Dess
Progress Telerik
Hi Dess,
Thank you for your reply. I am still getting the scroll in my chart.
Regards,
Manasa
It is normal to obtain a scrollbar if the RadListViewElement which hosts the legend items doesn't fit the available space below the chart. You can specify the MinSize property to a specific size that fits all items in the CreateChildElements method. However, if you shrink the chart and RadListViewElement respectively, the scrollbars won't be shown and the items will be clipped.
I hope this information helps. If you have any additional questions, please let me know.
Dess
Progress Telerik
Hi Dess,
I am creating chart in server side and exporting it as an image. Below is my code. I am using MyChart which inherits Telerik.WinControls.UI.RadChartView.
Dim radChartView = New MyChart
radChartView.ShowLegend = True
radChartView.ShowTitle = True
radChartView.Title = "Annual education cost analysis"
radChartView.ChartElement.TitleElement.TextAlignment = ContentAlignment.TopCenter
radChartView.ChartElement.LegendElement.TitleElement.Font = New Font(FontType, 15.0F, FontStyle.Regular)
radChartView.ChartElement.LegendElement.TitlePosition = Telerik.WinControls.UI.TitlePosition.Top
radChartView.ChartElement.LegendElement.TitleElement.ForeColor = Color.FromArgb(51, 51, 51)
radChartView.ChartElement.LegendPosition = Telerik.WinControls.UI.LegendPosition.Float
radChartView.ChartElement.LegendElement.StackElement.Orientation = System.Windows.Forms.Orientation.Horizontal
radChartView.ChartElement.LegendOffset = New Point(100, radChartView.Size.Height + 10)
radChartView.Area.View.Palette = CustomTelerikPalette
radChartView.Size = New System.Drawing.Size(600, 400)
Dim annualContributionLineSeries = New Telerik.WinControls.UI.LineSeries()
annualContributionLineSeries.PointSize = New SizeF(10, 10)
annualContributionLineSeries.LegendTitle = "Annual Contribution Amount"
annualContributionLineSeries.BorderWidth = 2
annualContributionLineSeries.DataSource = chartData.AnnualContributionAmount
annualContributionLineSeries.ValueMember = "Balance"
annualContributionLineSeries.CategoryMember = "FinanceYear"
annualContributionLineSeries.BackColor = Color.Red
radChartView.Series.Add(annualContributionLineSeries)
Dim chartTitle = LegendTitle(calculatorOutput)
Dim barSeriesList As New List(Of Telerik.WinControls.UI.BarSeries)
For index = 0 To calculatorOutput.CostList.individualCost.Count - 1
Dim barSeries = New Telerik.WinControls.UI.BarSeries
barSeries.LegendTitle = chartTitle(index)
barSeries.CombineMode = Telerik.Charting.ChartSeriesCombineMode.Stack
barSeriesList.Add(barSeries)
Next
Dim startYear = chartData.AnnualContributionAmount(0).FinanceYear
Dim eachChildren = 0
For Each item In barSeriesList
For i = 0 To calculatorOutput.CostList.individualCost(0).Count - 1
item.DataPoints.Add(New Telerik.Charting.CategoricalDataPoint(calculatorOutput.CostList.individualCost(eachChildren)(i), startYear + i))
Next
eachChildren += 1
Next
radChartView.Series.AddRange(barSeriesList.ToArray())
Dim yAxis As Telerik.WinControls.UI.LinearAxis = TryCast(radChartView.Axes(1), Telerik.WinControls.UI.LinearAxis)
yAxis.LabelFormat = "{0:c0}"
Dim xAxis As Telerik.WinControls.UI.CategoricalAxis = TryCast(radChartView.Axes(0), Telerik.WinControls.UI.CategoricalAxis)
xAxis.LabelFitMode = Telerik.Charting.AxisLabelFitMode.Rotate
xAxis.LabelRotationAngle = 90
Dim ms = New MemoryStream()
radChartView.ExportToImage(ms, radChartView.Size, System.Drawing.Imaging.ImageFormat.Jpeg)
ms.Seek(0, SeekOrigin.Begin)
Return ms
End Function
I am attaching my output which is an image.
Hi Dess,
Thank you for your help. I am able to display legends in 2 lines. But the marker is not visible in the legend of chart. I have uploaded both actual and expected legend markers.
Regards,
Manasa
You can show the check-boxes in the RadListViewElement which is used for the legend items and color the check-boxes n the color of the series. Here is demonstrates a sample code snippet which result is illustrated in the below screenshot:
Friend
Class
MyLegendElement
Inherits
ChartLegendElement
Private
panel
As
RadListViewElement
Public
Sub
New
(chartElement
As
RadChartElement)
MyBase
.
New
(chartElement)
End
Sub
Protected
Overrides
Sub
OnLegendInfosCollectionChanged(e
As
Telerik.WinControls.Data.NotifyCollectionChangedEventArgs, providerChange
As
Boolean
)
MyBase
.OnLegendInfosCollectionChanged(e, providerChange)
If
e.Action = Telerik.WinControls.Data.NotifyCollectionChangedAction.Add
Then
Dim
li
As
LegendItem = TryCast(e.NewItems(0), LegendItem)
panel.Items.Add(li.Title)
panel.Items.Last().Tag = li.Element
End
If
panel.SelectedIndex = -1
End
Sub
Protected
Overrides
Sub
CreateChildElements()
MyBase
.CreateChildElements()
panel =
New
RadListViewElement()
AddHandler
panel.VisualItemFormatting,
AddressOf
ListView_VisualItemFormatting
panel.ShowCheckBoxes =
True
panel.StretchHorizontally =
True
panel.StretchVertically =
False
panel.ViewType = ListViewType.IconsView
panel.ItemSize =
New
Drawing.Size(100, 20)
panel.ShouldHandleMouseInput =
True
panel.NotifyParentOnMouseInput =
False
panel.MaxSize =
New
Drawing.Size(500, 100)
panel.MinSize =
New
Drawing.Size(420, 100)
Me
.StackElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed
Me
.Children.Add(panel)
End
Sub
Protected
Overrides
ReadOnly
Property
ThemeEffectiveType()
As
Type
Get
Return
GetType
(ChartLegendElement)
End
Get
End
Property
Private
Sub
ListView_VisualItemFormatting(sender
As
Object
, e
As
ListViewVisualItemEventArgs)
Dim
checkBox
As
ListViewItemCheckbox = TryCast(e.VisualItem.ToggleElement, ListViewItemCheckbox)
If
checkBox IsNot
Nothing
Then
e.VisualItem.ToggleElement.ShouldHandleMouseInput =
False
e.VisualItem.ToggleElement.NotifyParentOnMouseInput =
False
checkBox.CheckMarkPrimitive.Fill.BackColor =
DirectCast
(e.VisualItem.Data.Tag, LineSeries).BorderColor
checkBox.CheckMarkPrimitive.Fill.GradientStyle = Telerik.WinControls.GradientStyles.Solid
checkBox.CheckMarkPrimitive.Border.Visibility = Telerik.WinControls.ElementVisibility.Collapsed
End
If
End Sub
End
Class
Regards,
Dess
Progress Telerik
Hello Dess,
Thank you very much for the solution, it worked. I have a last question, I observed when I am adding bar and line series in a chart, the line series point is not in the middle of the bar. I am attaching the screenshots and have highlighted in yellow. I am also attaching stacked bar chart, size of bar is bigger and is in between the marker ticks. I have used horizontalAxis.PlotMode = Telerik.Charting.AxisPlotMode.OnTicksPadded
Regards,
Manasa
In order to place the points of the LineSeries you should set the LineSeries.CombineMode property to ChartSeriesCombineMode.None:
I hope this information helps. If you have any additional questions, please let me know.
Dess
Progress Telerik
Hello Dess,
Thank you very much for the solution.
Regards,
Manasa
Hello Dess,
I am trying to display the series title like a label in the chart. Could you please help me with that?
I am attaching my expected chart.
Regards,
Mansi
Grid line annotations may be suitable for achieving your goal. Please refer to the following help article: https://docs.telerik.com/devtools/winforms/chartview/features/annotations/grid-line
Should you have further questions please let me know.
Regards,
Dess
Progress Telerik
If you want to use the drill-down functionality in RadChartView, it is necessary to extend the previously provided code snippet and create a custom ChartWrapper. Then, override its DrillDown and DrillToIndex methods in order to reset the legend element and fill the left/right panels with the respective items.
public
Form1()
{
InitializeComponent();
Random rand =
new
Random();
StringBuilder sb =
new
StringBuilder();
for
(
int
i = 0; i < 8; i++)
{
LineSeries lineSeries =
new
LineSeries();
sb =
new
StringBuilder();
for
(
int
j = 0; j < i + 1; j++)
{
sb.Append(
"S0"
+ i);
}
lineSeries.PointSize =
new
SizeF(10, 10);
lineSeries.LegendTitle = sb.ToString();
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Jan"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Apr"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Jul"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Oct"
));
this
.radChartView1.Series.Add(lineSeries);
}
this
.radChartView1.ShowLegend =
true
;
this
.radChartView1.ChartElement.LegendPosition = LegendPosition.Bottom;
DrillDownController drillControler =
new
DrillDownController();
this
.radChartView1.Controllers.Add(drillControler);
radChartView1.Views.AddNew(
"Revenue by Month"
);
this
.radChartView1.Drill += RadChartView1_Drill;
this
.radChartView1.ShowDrillNavigation =
true
;
}
private
void
RadChartView1_Drill(
object
sender, DrillEventArgs e)
{
e.View.Series.Clear();
e.View.Axes.Clear();
Random rand =
new
Random();
switch
(e.Level)
{
case
0:
for
(
int
i = 0; i < 8; i++)
{
LineSeries lineSeries =
new
LineSeries();
StringBuilder sb =
new
StringBuilder();
sb =
new
StringBuilder();
for
(
int
j = 0; j < i + 1; j++)
{
sb.Append(
"S0"
+ i);
}
lineSeries.PointSize =
new
SizeF(10, 10);
lineSeries.LegendTitle = sb.ToString();
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Jan"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Apr"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Jul"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Oct"
));
e.View.Series.Add(lineSeries);
}
break
;
case
1:
if
(e.SelectedPoint !=
null
)
for
(
int
i = 0; i < 8; i++)
{
LineSeries lineSeries =
new
LineSeries();
StringBuilder sb =
new
StringBuilder();
sb =
new
StringBuilder();
for
(
int
j = 0; j < i + 1; j++)
{
sb.Append(
"S0"
+ i + DateTime.Now.ToLongTimeString());
}
lineSeries.PointSize =
new
SizeF(10, 10);
lineSeries.LegendTitle = sb.ToString();
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Jan"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Apr"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Jul"
));
lineSeries.DataPoints.Add(
new
CategoricalDataPoint(rand.Next(-50, 50),
"Oct"
));
e.View.Series.Add(lineSeries);
}
break
;
}
}
class
MyChart : RadChartView
{
protected
override
RadChartElement CreateChartElement()
{
return
new
MyChartElement();
}
}
class
MyChartElement : RadChartElement
{
protected
override
ChartLegendElement CreateChartLegendElement()
{
return
new
MyLegendElement(
this
);
}
protected
override
ChartWrapper CreateChartWrapperElement()
{
return
new
CustomChartWrapper();
}
protected
override
Type ThemeEffectiveType
{
get
{
return
typeof
(RadChartElement);
}
}
}
public
class
CustomChartWrapper : ChartWrapper
{
public
override
bool
DrillDown(DataPoint point)
{
bool
result =
base
.DrillDown(point);
((MyLegendElement)((RadChartView)
this
.ElementTree.Control).ChartElement.LegendElement).ResetLegend();
return
result;
}
public
override
bool
DrillUp()
{
bool
result =
base
.DrillUp();
((MyLegendElement)((RadChartView)
this
.ElementTree.Control).ChartElement.LegendElement).ResetLegend();
return
result;
}
public
override
bool
DrillToIndex(
int
viewIndex)
{
bool
result=
base
.DrillToIndex(viewIndex);
((MyLegendElement)((RadChartView)
this
.ElementTree.Control).ChartElement.LegendElement).ResetLegend();
return
result;
}
}
class
MyLegendElement : ChartLegendElement
{
StackLayoutElement leftPanel =
new
StackLayoutElement();
StackLayoutElement rightPanel =
new
StackLayoutElement();
public
MyLegendElement(RadChartElement chartElement) :
base
(chartElement)
{
}
protected
override
void
CreateChildElements()
{
base
.CreateChildElements();
this
.StackElement.Orientation = System.Windows.Forms.Orientation.Horizontal;
}
protected
override
void
OnLegendInfosCollectionChanged(Telerik.WinControls.Data.NotifyCollectionChangedEventArgs e,
bool
providerChange)
{
ResetLegend();
}
public
void
ResetLegend()
{
this
.StackElement.Children.Clear();
if
(!
this
.StackElement.Children.Contains(leftPanel))
{
this
.StackElement.Children.Add(leftPanel);
leftPanel.Orientation = System.Windows.Forms.Orientation.Vertical;
}
if
(!
this
.StackElement.Children.Contains(rightPanel))
{
this
.StackElement.Children.Add(rightPanel);
rightPanel.Orientation = System.Windows.Forms.Orientation.Vertical;
}
leftPanel.Children.Clear();
rightPanel.Children.Clear();
for
(
int
i = 0; i <
this
.Provider.LegendInfos.Count; i++)
{
LegendItemElement element =
this
.OnVisualItemCreating(
this
.Provider.LegendInfos[i]);
if
(i <
this
.Provider.LegendInfos.Count / 2)
{
leftPanel.Children.Add(element);
}
else
{
rightPanel.Children.Add(element);
}
}
}
protected
override
Type ThemeEffectiveType
{
get
{
return
typeof
(ChartLegendElement);
}
}
}
I hope this information helps.
Regards,
Dess | Tech Support Engineer, Sr.
Progress Telerik