I need to draw a series of graphs and show the legend. When the legend does not fit in the RadChartView, a scroll bar appears - this is acceptable, you can quickly see the whole legend. But the title of the legend is cut off.
If one sets the LabelsOffsetFromCenter property to any value there will be no change in the series labels on the chart.
If one removes the trackball controller while the trackball info element is visible it will remain on the chart. Steps to reproduce: 1. Add a chart to a form 2. Add series and data points 3. Subscribe for the chart MouseClick event 4. In the event handler change the value of the chart ShowTrackball property (from false to true or vice versa) Start the project and click several times on the chart. You will see that trackball info elements will remain on the chart.
radChartView1.AreaType = ChartAreaType.Cartesian;
var scatterSeries = new ScatterSeries();
scatterSeries.DataPoints.Add(new ScatterDataPoint(15, 19));
scatterSeries.DataPoints.Add(new ScatterDataPoint(18, 10));
scatterSeries.DataPoints.Add(new ScatterDataPoint(13, 15));
scatterSeries.DataPoints.Add(new ScatterDataPoint(10, 8));
scatterSeries.DataPoints.Add(new ScatterDataPoint(5, 12));
radChartView1.Series.Add(scatterSeries);
var verticalAxis = radChartView1.Axes.Get<LinearAxis>(1);
verticalAxis.Minimum = 0.0d;
verticalAxis.Maximum = 5.0d;
verticalAxis.MajorStep = 0.5d;
verticalAxis.LabelFormat = "{0:0.00} m";
for (var i = verticalAxis.Minimum; i <= verticalAxis.Maximum; i += verticalAxis.MajorStep)
{
var annotation1 = new CartesianGridLineAnnotation();
annotation1.Axis = this.radChartView1.Axes[1] as CartesianAxis;
annotation1.BorderColor = Color.LightGray;
annotation1.BorderDashStyle = DashStyle.Solid;
annotation1.BorderWidth = 1;
annotation1.Value = i;
radChartView1.Annotations.Add(annotation1);
}
Workaround:
public RadForm1()
{
InitializeComponent();
this.radChartView1.CreateRenderer += radChartView1_CreateRenderer;
InitChart();
}
private void radChartView1_CreateRenderer(object sender, ChartViewCreateRendererEventArgs e)
{
e.Renderer = new CustomRenderer(e.Area as CartesianArea);
}
public class CustomRenderer : CartesianRenderer
{
public CustomRenderer(CartesianArea area) : base(area)
{
}
protected override void InitializeAnnotations(AnnotationDrawMode drawMode)
{
for (int i = 0; i < this.Area.Annotations.Count; i++)
{
if (this.Area.Annotations[i] is CartesianGridLineAnnotation && this.Area.Annotations[i].DrawMode == drawMode)
{
this.DrawParts.Add(new CustomCartesianGridLineAnnotationDrawPart(this.Area.Annotations[i] as CartesianGridLineAnnotation, this));
}
}
}
}
public class CustomCartesianGridLineAnnotationDrawPart : CartesianGridLineAnnotationDrawPart
{
public CustomCartesianGridLineAnnotationDrawPart(CartesianGridLineAnnotation element, CartesianRenderer renderer) : base(element, renderer)
{
}
public override void Draw()
{
FieldInfo fi = typeof(CartesianGridLineAnnotation).GetField("model", BindingFlags.Instance | BindingFlags.NonPublic);
ChartAnnotationModel model = fi.GetValue(this.Element) as ChartAnnotationModel;
RectangleF rect = ChartRenderer.ToRectangleF(model.LayoutSlot);
rect.Offset(this.ViewportOffsetX, this.ViewportOffsetY);
rect.Offset(new PointF(0,1));
Graphics graphics = this.Renderer.Surface as Graphics;
RadGdiGraphics radGraphics = new RadGdiGraphics(graphics);
Rectangle clipRect = ChartRenderer.ToRectangle(this.Element.View.GetArea<CartesianArea>().AreaModel.PlotArea.LayoutSlot);
clipRect.Offset((int)this.ViewportOffsetX, (int)this.ViewportOffsetY);
graphics.SetClip(clipRect);
GraphicsPath path = new GraphicsPath();
path.AddLine(rect.Location, new PointF(rect.Right, rect.Bottom));
BorderPrimitiveImpl border = new BorderPrimitiveImpl(this.Element, null);
border.PaintBorder(radGraphics, null, path, rect);
rect.Size = graphics.MeasureString(this.Element.Label, this.Element.Font);
rect.Offset(this.Element.PositonOffset.Width + 1, this.Element.PositonOffset.Height + 1);
TextParams tp = new TextParams();
tp.font = this.Element.Font;
tp.foreColor = this.Element.ForeColor;
tp.paintingRectangle = new RectangleF(rect.X, rect.Y, rect.Height, rect.Width);
tp.text = this.Element.Label;
FillPrimitiveImpl fill = new FillPrimitiveImpl(this.Element, null);
fill.PaintFill(radGraphics, null, rect);
radGraphics.DrawString(tp, new SizeF(rect.Height, rect.Width));
}
}
Steps to reproduce: 1. Add a chart to a form 2. Add a PanZoomController with ChartPanZoomMode set to Both 3. Add a series with some data 4. Set the LabelFitMode of the horizontal axis to Rotate 5. Run the project and zoom in on the chart and then pan. You will see that when you pan vertically the labels of the horizontal axis will move in the wrong direction.
System.OverflowException: 'Value was either too large or too small for a Decimal.
To reproduce:
var lineSeries = new LineSeries();
lineSeries.DataPoints.Add(new CategoricalDataPoint(0, "A"));
lineSeries.DataPoints.Add(new CategoricalDataPoint(Convert.ToDouble(decimal.MaxValue), "B"));
lineSeries.DataPoints.Add(new CategoricalDataPoint(0, "C"));
lineSeries.DataPoints.Add(new CategoricalDataPoint(decimal.ToDouble(decimal.MaxValue), "D"));
lineSeries.DataPoints.Add(new CategoricalDataPoint(0, "E"));
this.radChartView1.Series.Add(lineSeries);
Please use the following code snippet. You will notice that for very long text in the trackball, the fill rectangle doesn't fit the text.
PS. If the legend items occupy enough width of the chart, there wouldn't be sufficient space for the trackball.
public RadForm1()
{
InitializeComponent();
BarSeries barSeries = new BarSeries("Performance", "RepresentativeName");
barSeries.LegendTitle = "Q1 This is some sample very long text";
barSeries.DataPoints.Add(new CategoricalDataPoint(177, "Harley"));
barSeries.DataPoints.Add(new CategoricalDataPoint(128, "White"));
barSeries.DataPoints.Add(new CategoricalDataPoint(143, "Smith"));
barSeries.DataPoints.Add(new CategoricalDataPoint(111, "Jones"));
barSeries.DataPoints.Add(new CategoricalDataPoint(118, "Marshall"));
this.radChartView1.Series.Add(barSeries);
BarSeries barSeries2 = new BarSeries("Performance", "RepresentativeName");
barSeries2.LegendTitle = "Q2 This is some sample very long text";
barSeries2.DataPoints.Add(new CategoricalDataPoint(153, "Harley"));
barSeries2.DataPoints.Add(new CategoricalDataPoint(141, "White"));
barSeries2.DataPoints.Add(new CategoricalDataPoint(130, "Smith"));
barSeries2.DataPoints.Add(new CategoricalDataPoint(88, "Jones"));
barSeries2.DataPoints.Add(new CategoricalDataPoint(109, "Marshall"));
this.radChartView1.Series.Add(barSeries2);
this.radChartView1.ShowLegend = true;
ChartTrackballController trackballController = new ChartTrackballController();
trackballController.TextNeeded += trackballController_TextNeeded;
radChartView1.Controllers.Add(trackballController);
}
string text = "<html><color=200,200,200,200>This is some sample very long text that wouldn't fit in " +
"the default size of the RadChartView from the Telerik UI for WinForms suite</html>";
private void trackballController_TextNeeded(object sender, TextNeededEventArgs e)
{
e.Text = text;
}
Workaround:
ChartTrackballController trackballController = new ChartTrackballController();
trackballController.IsFixedSize = true;
trackballController.FixedSize = new Size(700, 40);
trackballController.TextNeeded += trackballController_TextNeeded;
radChartView1.Controllers.Add(trackballController);
Please use the following code snippet:
public RadForm1()
{
InitializeComponent();
this.radChartView1.View.AreaType = ChartAreaType.Cartesian;
RangeBarSeries rangeBarSeries = new RangeBarSeries();
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 14, DateTime.Now.TimeOfDay.TotalMinutes + 10, "5/17/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 7, DateTime.Now.TimeOfDay.TotalMinutes + 5, "5/17/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 4, DateTime.Now.TimeOfDay.TotalMinutes + 2, "5/17/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 30, DateTime.Now.TimeOfDay.TotalMinutes + 10, "5/18/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 7, DateTime.Now.TimeOfDay.TotalMinutes + 5, "5/18/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 4, DateTime.Now.TimeOfDay.TotalMinutes + 2, "5/19/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes - 89, DateTime.Now.TimeOfDay.TotalMinutes - 100, "5/20/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 7, DateTime.Now.TimeOfDay.TotalMinutes + 5, "5/20/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes - 79, DateTime.Now.TimeOfDay.TotalMinutes - 90, "5/21/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 7, DateTime.Now.TimeOfDay.TotalMinutes + 5, "5/21/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 14, DateTime.Now.TimeOfDay.TotalMinutes + 10, "5/22/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 7, DateTime.Now.TimeOfDay.TotalMinutes + 5, "5/22/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 14, DateTime.Now.TimeOfDay.TotalMinutes + 10, "5/23/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 7, DateTime.Now.TimeOfDay.TotalMinutes + 5, "5/23/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 14, DateTime.Now.TimeOfDay.TotalMinutes + 10, "5/25/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 7, DateTime.Now.TimeOfDay.TotalMinutes + 5, "5/24/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 14, DateTime.Now.TimeOfDay.TotalMinutes + 10, "5/26/2021"));
rangeBarSeries.DataPoints.Add(new RangeDataPoint(DateTime.Now.TimeOfDay.TotalMinutes + 7, DateTime.Now.TimeOfDay.TotalMinutes + 5, "5/26/2021"));
this.radChartView1.View.Series.Add(rangeBarSeries);
rangeBarSeries.VerticalAxis.LabelRotationAngle = -45;
rangeBarSeries.VerticalAxis.LabelFitMode = AxisLabelFitMode.Rotate;
LinearAxis verticalAxis = this.radChartView1.View.Axes.Get<LinearAxis>(1);
verticalAxis.Minimum = 0; //Minutes 0:00
verticalAxis.Maximum = 1440; //Minutes 23:00
verticalAxis.MajorStep = 60; //60 minutes in an hour
verticalAxis.LastLabelVisibility = AxisLastLabelVisibility.Hidden;
}
When the labels are not rotated:
When rotated:
Steps to reproduce: 1. Add a chart to a form 2. Add a bar series with some data 3. Set the gapLength of the horizontal axis to 0 Run the project and resize the chart. You will see that the gaps between bars are inconsistent.
Please use the following code snippet and click the button to print the chart:
public RadForm1()
{
InitializeComponent();
Random rand = new Random();
for (int i = 0; i < 50; i++)
{
LineSeries lineSeries = new LineSeries();
lineSeries.LegendTitle = "Series" + i;
lineSeries.DataPoints.Add(new CategoricalDataPoint(rand.Next(0,20), "Jan"));
lineSeries.DataPoints.Add(new CategoricalDataPoint(rand.Next(0,20), "Apr"));
lineSeries.DataPoints.Add(new CategoricalDataPoint(rand.Next(0,20), "Jul"));
lineSeries.DataPoints.Add(new CategoricalDataPoint(rand.Next(0,20), "Oct"));
this.radChartView1.Series.Add(lineSeries);
}
this.radChartView1.ShowLegend = true;
this.radChartView1.ChartElement.LegendPosition = LegendPosition.Bottom;
}
private void radButton1_Click(object sender, EventArgs e)
{
this.radChartView1.PrintPreview();
}
Expected:
Actual:
Workaround:
https://docs.telerik.com/devtools/winforms/knowledge-base/chartview-wrap-legend-items
internal class MyChart : RadChartView
{
protected override RadChartElement CreateChartElement()
{
return new MyChartElement();
}
}
internal class MyChartElement : RadChartElement
{
protected override ChartLegendElement CreateChartLegendElement()
{
return new MyLegendElement(this);
}
protected override Type ThemeEffectiveType
{
get
{
return typeof(RadChartElement);
}
}
}
internal class MyLegendElement : ChartLegendElement
{
private RadListViewElement panel;
public MyLegendElement(RadChartElement chartElement) : base(chartElement)
{
}
protected override void OnLegendInfosCollectionChanged(Telerik.WinControls.Data.NotifyCollectionChangedEventArgs e, bool providerChange)
{
base.OnLegendInfosCollectionChanged(e, providerChange);
if (e.Action == Telerik.WinControls.Data.NotifyCollectionChangedAction.Add)
{
LegendItem li = e.NewItems[0] as LegendItem;
panel.Items.Add(li.Title);
panel.Items.Last().Tag = li.Element;
}
panel.SelectedIndex = -1;
}
protected override void CreateChildElements()
{
base.CreateChildElements();
panel = new RadListViewElement();
panel.VisualItemFormatting += ListView_VisualItemFormatting;
panel.ShowCheckBoxes = true;
panel.StretchHorizontally = true;
panel.StretchVertically = false;
panel.ViewType = ListViewType.IconsView;
panel.ItemSize = new System.Drawing.Size(100, 20);
panel.ShouldHandleMouseInput = true;
panel.NotifyParentOnMouseInput = false;
panel.MaxSize = new System.Drawing.Size(int.MaxValue, 200);
this.StackElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
this.Children.Add(panel);
}
protected override Type ThemeEffectiveType
{
get
{
return typeof(ChartLegendElement);
}
}
private void ListView_VisualItemFormatting(object sender, ListViewVisualItemEventArgs e)
{
ListViewItemCheckbox checkBox = e.VisualItem.ToggleElement as ListViewItemCheckbox;
if (checkBox != null)
{
e.VisualItem.ToggleElement.ShouldHandleMouseInput = false;
e.VisualItem.ToggleElement.NotifyParentOnMouseInput = false;
checkBox.CheckMarkPrimitive.Fill.BackColor = ((LineSeries)(e.VisualItem.Data.Tag)).BorderColor;
checkBox.CheckMarkPrimitive.Fill.GradientStyle = Telerik.WinControls.GradientStyles.Solid;
checkBox.CheckMarkPrimitive.Border.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
}
}
}
Please refer to the attached sample project. Try to select a point.
Expected result: the clicked point should be colored in red.
Actual result: a random point is colored in red even though the label is colored correctly. The attached gif file illustrates the observed result.
Add several data points with date time objects as their categories. Make sure the time span these date time objects is within a few seconds. You will see that not all labels will be displayed by the chart.
When the legend has many items a scrollbar should appear.