Before zoom:
After zoom:
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.
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);
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));
}
}
Hi team,
We need a ChartView with multiple series and multiple Y-axis. The axis color of each Y-axis should be automatically painted according to the palette setting (thank you for the brilliant work - it's very intuitive). However, if clear the series and re-assign a new set of series, the border color of the first axis changes to black, regardless which palette is active. If the palette is set to a new one, the border color can be re-painted correctly. See screenshot as attached.
How to reproduce: Please refer to the attached project for a demo of reproduction. Click the first button to populate new random data. The border color of the first axis should change to black after clicking the button twice and more times. Clicking the second button will force the palette to change and the border color will become normal.
Thank you, team.
Best,
Yusi
When you have BarSeries and LineSeries in RadChartView the problem is that the DataPoint.Presenter is always BarSerries, never LineSeries.
To workaround, create custom renderer:
this.radChartView1.CreateRenderer += this.RadChartView1_CreateRenderer;
private void RadChartView1_CreateRenderer(object sender, ChartViewCreateRendererEventArgs e)
{
e.Renderer = new CustomCartesianRenderer(e.Area as CartesianArea);
}
public class CustomCartesianRenderer : CartesianRenderer
{
public CustomCartesianRenderer(CartesianArea area)
: base(area)
{ }
public override DataPoint HitTest(int x, int y)
{
for (int i = this.DrawParts.Count - 1; i >= 0; i--)
{
DataPoint dataPoint = this.DrawParts[i].HitTest(new Point(x, y));
if (dataPoint != null)
{
return dataPoint;
}
}
return base.HitTest(x, y);
}
}
Use attached to reproduce.
- Click at least 7 times.
Workaround: Crete new series instance each time.
Use attached to reproduce.
Workaround:
series.DataPoints.Add(new PieDataPoint(0.01, "Germany"));
After 1 million the decimal places of the labels are not correct, In your image. the labels on the horizontal axis go 999,992.50 - 999,995.00 - 999,997.5 - 1,000,000.00 - *1,000,003.00(should be 1,000,002.50) - 1,000,005.00 - *1,000,008.00(should be 1,000,007.5)
To reproduce: WaterfallSeries series = new WaterfallSeries(); series.ShowLabels = true; series.DataPoints.Add(new WaterfallDataPoint(50000, false, false, "Beginning\nBalance")); series.DataPoints.Add(new WaterfallDataPoint(17000, false, false, "Jan")); series.DataPoints.Add(new WaterfallDataPoint(14000, false, false, "Feb")); series.DataPoints.Add(new WaterfallDataPoint(-12000, false, false, "Mar")); series.DataPoints.Add(new WaterfallDataPoint(69000, true, false, "Q1")); series.DataPoints.Add(new WaterfallDataPoint(-22000, false, false, "Apr")); series.DataPoints.Add(new WaterfallDataPoint(-18000, false, false, "May")); series.DataPoints.Add(new WaterfallDataPoint(500, false, false, "Jun")); series.DataPoints.Add(new WaterfallDataPoint(-30000, true, false, "Q2")); series.DataPoints.Add(new WaterfallDataPoint(39000, false, true, "Ending\nBalance")); this.radChartView1.Series.Add(series); CartesianGridLineAnnotation annotation1 = new CartesianGridLineAnnotation(); annotation1.Label = "Annotation"; annotation1.ForeColor = Color.Lime; annotation1.BackColor = Color.Black; this.radChartView1.Annotations.Add(annotation1); Workaround: public RadForm1() { InitializeComponent(); this.radChartView1.CreateRenderer += radChartView1_CreateRenderer; WaterfallSeries series = new WaterfallSeries(); series.ShowLabels = true; series.DataPoints.Add(new WaterfallDataPoint(50000, false, false, "Beginning\nBalance")); series.DataPoints.Add(new WaterfallDataPoint(17000, false, false, "Jan")); series.DataPoints.Add(new WaterfallDataPoint(14000, false, false, "Feb")); series.DataPoints.Add(new WaterfallDataPoint(-12000, false, false, "Mar")); series.DataPoints.Add(new WaterfallDataPoint(69000, true, false, "Q1")); series.DataPoints.Add(new WaterfallDataPoint(-22000, false, false, "Apr")); series.DataPoints.Add(new WaterfallDataPoint(-18000, false, false, "May")); series.DataPoints.Add(new WaterfallDataPoint(500, false, false, "Jun")); series.DataPoints.Add(new WaterfallDataPoint(-30000, true, false, "Q2")); series.DataPoints.Add(new WaterfallDataPoint(39000, false, true, "Ending\nBalance")); this.radChartView1.Series.Add(series); CartesianGridLineAnnotation annotation1 = new CartesianGridLineAnnotation(); annotation1.Label = "Annotation"; annotation1.ForeColor = Color.Lime; annotation1.BackColor = Color.Black; annotation1.PositonOffset = new SizeF(0, -20); annotation1.Axis = this.radChartView1.Axes[1] as CartesianAxis; annotation1.Value = 70000; annotation1.BorderColor = Color.Red; annotation1.BorderDashStyle = DashStyle.Solid; annotation1.BorderWidth = 1; this.radChartView1.Annotations.Add(annotation1); } private void radChartView1_CreateRenderer(object sender, ChartViewCreateRendererEventArgs e) { e.Renderer = new CustomCartesianRenderer(e.Area as CartesianArea); } public class CustomCartesianRenderer : CartesianRenderer { public CustomCartesianRenderer(CartesianArea area) : base(area) { } protected override void Initialize() { base.Initialize(); for (int i = 0; i <= this.DrawParts.Count - 1; i++) { CartesianGridLineAnnotationDrawPart annotationPart = this.DrawParts[i] as CartesianGridLineAnnotationDrawPart; if (annotationPart != null) { this.DrawParts[i] = new CustomCartesianGridLineAnnotationDrawPart((CartesianGridLineAnnotation)annotationPart.Element, 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.NonPublic | BindingFlags.Instance); ChartAnnotationModel model = fi.GetValue(this.Element) as ChartAnnotationModel; RectangleF rect = ChartRenderer.ToRectangleF(model.LayoutSlot); rect.Offset(this.ViewportOffsetX, this.ViewportOffsetY); 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 = rect; tp.text = this.Element.Label; FillPrimitiveImpl fill = new FillPrimitiveImpl(this.Element, null); fill.PaintFill(radGraphics, null, rect); TextPrimitiveHtmlImpl text = new TextPrimitiveHtmlImpl(); text.PaintPrimitive(radGraphics, 0f, new SizeF(1f, 1f), tp); } }
To reproduce: - Add a chart to the form and set series with DataSource - Close and dispose the form Workaround: Set the DataSource property of the series to null prior closing.
How to reproduce: private void UpdateChart() { this.radChartView1.Series.Clear(); // Create two series for the bar chart. BarSeries requiredBarSeries = new BarSeries { ShowLabels = true, CombineMode = ChartSeriesCombineMode.Cluster, NumberOfColors = 2, }; BarSeries actualBarSeries = new BarSeries { ShowLabels = true, CombineMode = ChartSeriesCombineMode.Cluster, NumberOfColors = 2, }; // Add the data. AddDataPoint(requiredBarSeries, .0333d, "Germany", "Required"); AddDataPoint(actualBarSeries, .050d, "Germany", "Actual"); AddDataPoint(requiredBarSeries, .0333d, "United States", "Required"); AddDataPoint(actualBarSeries, .050d, "United States", "Actual"); AddDataPoint(requiredBarSeries, .00d, "France", "Required"); AddDataPoint(actualBarSeries, .050d, "France", "Actual"); AddDataPoint(requiredBarSeries, 0.0d, "United Kingdom", "Required"); AddDataPoint(actualBarSeries, .050d, "United Kingdom", "Actual"); AddDataPoint(requiredBarSeries, 0.955d, "Russia", "Required"); // Change the following value to .95d to see // the issue. AddDataPoint(actualBarSeries, .15d, "Russia", "Actual"); this.radChartView1.Series.Add(requiredBarSeries); this.radChartView1.Series.Add(actualBarSeries); CategoricalAxis horizontalAxis = radChartView1.Axes[0] as CategoricalAxis; horizontalAxis.LabelFitMode = AxisLabelFitMode.MultiLine; } private void AddDataPoint(BarSeries series, double val, string category, string label) { series.DataPoints.Add(new CategoricalDataPoint { Value = val, Label = String.Format("{0}\n{1:P2}", label, val), Category = category }); } Workaround: create a custom SmartLabelsController public RadForm1() { InitializeComponent(); SmartLabelsController labelsController = new CustomSmartLabelsController(); this.radChartView1.Controllers.Add(labelsController); // Set up the chart } public class CustomSmartLabelsController : SmartLabelsController { protected override SmartLabelsStrategyBase GetDefaultStrategy(ChartArea area) { SmartLabelsStrategyBase strategy = base.GetDefaultStrategy(area); if (strategy is VerticalAdjusmentLabelsStrategy) { strategy = new CustomVerticalAdjusmentLabelsStrategy(); Dictionary<Type, List<Type>> strategies = typeof(SmartLabelsController).GetField("strategySeries", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(this) as Dictionary<Type, List<Type>>; strategies.Remove(typeof(VerticalAdjusmentLabelsStrategy)); strategies.Add(typeof(CustomVerticalAdjusmentLabelsStrategy), new List<Type> { typeof(BarSeries), typeof(LineSeriesBase) }); } return strategy; } } public class CustomVerticalAdjusmentLabelsStrategy : VerticalAdjusmentLabelsStrategy { public override void CalculateLocations(ChartSeriesCollection series, Rectangle plotArea) { if (series.Count == 0) { return; } List<LabelElement> labels = new List<LabelElement>(); List<int> overlaps = new List<int>(); foreach (ChartSeries chartSeries in series) { if (!chartSeries.ShowLabels || !chartSeries.IsVisible) { continue; } foreach (DataPointElement point in chartSeries.Children) { LabelElement label = (LabelElement)point.Children[0]; Rectangle labelRect = ChartRenderer.ToRectangle(label.GetLayoutSlot()); labelRect.X += (int)(series[0].View.Viewport.X + ((IChartView)series[0].View).PlotOriginX); labelRect.Y += (int)(series[0].View.Viewport.Y + ((IChartView)series[0].View).PlotOriginY); if (chartSeries.View.GetArea<CartesianArea>().Orientation == Orientation.Vertical) { labelRect.Y -= this.DistanceToLabel; } else { labelRect.X += this.DistanceToLabel; } labelRect.Inflate(0, this.DistanceBetweenLabels); label.SmartRectangle = labelRect; labels.Add(label); } } CartesianSeries cartesianSeries = (CartesianSeries)series[0]; if (cartesianSeries != null) { this.RestrictWithinAxes(labels, cartesianSeries); } LabelElement labelToMove = this.GetElementWithMostOverlaps(labels, series); int counter = 0; while (labelToMove != null && counter < labels.Count) { Rectangle firstDirectionRect; Rectangle secondDirectionRect; int firstMoveCost; int secondMoveCost; Rectangle dataPointLayout = ChartRenderer.ToRectangle(labelToMove.DataPoint.LayoutSlot); dataPointLayout.X += (int)labelToMove.View.Viewport.X; dataPointLayout.Y += (int)labelToMove.View.Viewport.Y; if (cartesianSeries.View.GetArea<CartesianArea>().Orientation == System.Windows.Forms.Orientation.Vertical) { firstDirectionRect = this.GetBestPositionInUpwardDirection(labels, labelToMove, cartesianSeries); secondDirectionRect = this.GetBestPositionInDownwardDirection(labels, labelToMove, cartesianSeries); firstMoveCost = Math.Abs(labelToMove.SmartRectangle.Y - firstDirectionRect.Y); secondMoveCost = Math.Abs(labelToMove.SmartRectangle.Y - secondDirectionRect.Y); } else { firstDirectionRect = this.GetBestPositionInLeftDirection(labels, labelToMove, cartesianSeries); secondDirectionRect = this.GetBestPositionInRightDirection(labels, labelToMove, cartesianSeries); firstMoveCost = Math.Abs(dataPointLayout.X - firstDirectionRect.X); secondMoveCost = Math.Abs(dataPointLayout.X - secondDirectionRect.X); } if (!dataPointLayout.IntersectsWith(secondDirectionRect) && firstMoveCost > secondMoveCost) { labelToMove.SmartRectangle = secondDirectionRect; } else { labelToMove.SmartRectangle = firstDirectionRect; } labelToMove = this.GetElementWithMostOverlaps(labels, series); counter++; } this.FinalPositionsOptimization(labels); foreach (LabelElement label in labels) { Rectangle rect = label.SmartRectangle; rect.Inflate(0, -this.DistanceBetweenLabels); Rectangle dataPointLayout = ChartRenderer.ToRectangle(label.DataPoint.LayoutSlot); dataPointLayout.X += (int)cartesianSeries.View.Viewport.X; dataPointLayout.Y += (int)cartesianSeries.View.Viewport.Y; int delta = 1; if (dataPointLayout.Y > label.SmartRectangle.Y) { delta = -1; } rect.Y += delta * this.DistanceToLabel; label.SmartRectangle = rect; } } }
To reproduce: run the attached sample project and you will notice that the data points are not properly aligned. Workaround: use equal number of data points for the series.
How to reproduce: the issue can be observed when opening a form with a RadChartView which is not visible located in RadScrollablePanel. The panel will scroll to the chart which is not desired Workaround: public partial class RadForm1 : Telerik.WinControls.UI.RadForm { public RadForm1() { InitializeComponent(); this.radScrollablePanel1.AllowAutomaticScrollToControl = false; } protected override void OnVisibleChanged(EventArgs e) { base.OnVisibleChanged(e); this.radScrollablePanel1.HorizontalScrollbar.Value = 0;; } }
How to reproduce: Check the attached project Workaround: Create a separate custom MACD indicator and add it to the chart, uncomment the commented code in the attached project Friend Class MacdCustomIndicator Inherits MacdIndicator Private customBorderColor As Color Public Property BorderColor() As Color Get Return customBorderColor End Get Set(ByVal value As Color) customBorderColor = value Me.ChildIndicator.BorderColor = value End Set End Property Sub New() Dim customMacdInnerIndicator = New CustomMacdInnerIndicator(Me) Me.GetType().BaseType.GetField("childIndicator", BindingFlags.Instance Or BindingFlags.NonPublic).SetValue(Me, customMacdInnerIndicator) End Sub End Class Friend Class CustomMacdInnerIndicator Inherits MacdInnerIndicator Public Sub New(owner As MacdIndicator) MyBase.New(owner) End Sub Public Overrides Function GetProcessedValue(currentIndex As Integer) As Double Dim macd As Double = Me.CalculateMacdValue(currentIndex, LongPeriod, ShortPeriod) Me.Cache(macdValues).Add(currentIndex, macd) Return macd End Function End Class
To reproduce: - The total amount should go bellow 0 with the last point: var ws = new WaterfallSeries(); ws.ShowLabels = true; ws.DataPoints.Add(new Telerik.Charting.WaterfallDataPoint(10.0, false, false)); ws.DataPoints.Add(new Telerik.Charting.WaterfallDataPoint(2.0, false, false)); ws.DataPoints.Add(new Telerik.Charting.WaterfallDataPoint(3.0, false, false)); ws.DataPoints.Add(new Telerik.Charting.WaterfallDataPoint(-20.0, false, false)); radChartView1.Series.Add(ws); Workaround: Set the minimum: var verticalAxis = radChartView1.Axes[1] as LinearAxis; verticalAxis.Minimum = -10;