Currently, VisualStudio2012DarkTheme has a white background in order to be able to read the labels. This change was done when addressing this item:
However, it is inconsistent a dark theme to have a white background color. The design should be improved to achieve consistent look and feel.
Public Class RadForm2 Public Sub New() InitializeComponent() AddHandler Me.RadChartView1.CreateRenderer, AddressOf radChartView1_CreateRenderer Me.RadChartView1.ShowSmartLabels = True Me.RadChartView1.ShowPanZoom = True Dim barSeries As New BarSeries() Dim barSeries1 As New BarSeries() Dim barSeries2 As New BarSeries() Dim rand As New Random() barSeries.DataPoints.Add(New CategoricalDataPoint(101, 0)) barSeries1.DataPoints.Add(New CategoricalDataPoint(101, 0)) barSeries2.DataPoints.Add(New CategoricalDataPoint(101, 0)) For i As Integer = 1 To 9 barSeries.DataPoints.Add(New CategoricalDataPoint(rand.[Next](100), i)) barSeries1.DataPoints.Add(New CategoricalDataPoint(rand.[Next](100), i)) barSeries2.DataPoints.Add(New CategoricalDataPoint(rand.[Next](100), i)) Next barSeries.ShowLabels = True barSeries.DrawLinesToLabels = True barSeries1.ShowLabels = True barSeries1.DrawLinesToLabels = True barSeries2.ShowLabels = True barSeries2.DrawLinesToLabels = True Me.RadChartView1.Series.Add(barSeries) Me.RadChartView1.Series.Add(barSeries1) Me.RadChartView1.Series.Add(barSeries2) End Sub Private Sub radChartView1_CreateRenderer(sender As Object, e As ChartViewCreateRendererEventArgs) 'e.Renderer = New CustomCartesianRenderer(TryCast(e.Area, CartesianArea)) End Sub End Class Workaround: Create a custom renderer Public Class CustomCartesianRenderer Inherits CartesianRenderer Public Sub New(area As CartesianArea) MyBase.New(area) End Sub Protected Overrides Sub Initialize() MyBase.Initialize() For i As Integer = 0 To Me.DrawParts.Count - 1 Dim labelPart As BarLabelElementDrawPart = TryCast(Me.DrawParts(i), BarLabelElementDrawPart) If labelPart IsNot Nothing Then Me.DrawParts(i) = New CustomBarLabelElementDrawPart(DirectCast(labelPart.Element, BarSeries), Me) End If Next End Sub End Class Public Class CustomBarLabelElementDrawPart Inherits BarLabelElementDrawPart Public Sub New(owner As ChartSeries, renderer As IChartRenderer) MyBase.New(owner, renderer) End Sub Public Overrides Sub Draw() Dim graphics As Graphics = TryCast(Me.Renderer.Surface, Graphics) Dim cartesianSeries As CartesianSeries = TryCast(Me.Element, CartesianSeries) If cartesianSeries IsNot Nothing Then Dim area As CartesianArea = DirectCast(cartesianSeries.[GetType]().GetField("area", BindingFlags.Instance Or BindingFlags.NonPublic).GetValue(cartesianSeries), CartesianArea) Dim clipRect As RectangleF = DirectCast(area.[GetType]().GetMethod("GetCartesianClipRect", BindingFlags.Instance Or BindingFlags.NonPublic).Invoke(area, New Object() {}), RectangleF) graphics.SetClip(clipRect) End If MyBase.Draw() graphics.ResetClip() End Sub Protected Overrides Function GetLineStart(label As LabelElement, point As DataPointElement, isSmartLabel As Boolean) As PointF Dim lineStart As PointF = MyBase.GetLineStart(label, point, isSmartLabel) Dim x As Single = CSng(TryCast(Me.Element.View, IChartView).PlotOriginX) Dim y As Single = CSng(TryCast(Me.Element.View, IChartView).PlotOriginY) lineStart.X += x lineStart.Y += y Return lineStart End Function Protected Overrides Function GetLineEnd(label As LabelElement, point As DataPointElement, isSmartLabel As Boolean) As PointF Dim lineEnd As PointF = MyBase.GetLineEnd(label, point, isSmartLabel) If Not isSmartLabel Then Dim x As Single = CSng(TryCast(Me.Element.View, IChartView).PlotOriginX) Dim y As Single = CSng(TryCast(Me.Element.View, IChartView).PlotOriginY) lineEnd.X += x lineEnd.Y += y End If Return lineEnd End Function End Class
To reproduce: - Set the position like this: this.radChartView1.ChartElement.LegendElement.Alignment = ContentAlignment.TopCenter; - Export the chart to an image, the position is not the same as in the application. Workaround: - Set the position manually: this.radChartView1.ChartElement.LegendPosition = LegendPosition.Float; this.radChartView1.ChartElement.LegendOffset = new Point(400, 0);
How to reproduce: Public Class Form1 Sub New() InitializeComponent() Me.SetupLineSeries() End Sub Private Sub SetupLineSeries() Dim splitContainer = New RadSplitContainer() splitContainer.SplitPanels.Add(New SplitPanel()) splitContainer.SplitPanels.Add(New SplitPanel()) splitContainer.SplitPanels(0).Controls.Add(Me.RadChartView1) Me.RadChartView1.Dock = DockStyle.Fill splitContainer.Orientation = Orientation.Horizontal splitContainer.Parent = Me splitContainer.Dock = DockStyle.Fill Dim lineSeries As New Telerik.WinControls.UI.LineSeries("2014") lineSeries.LegendTitle = "2014" lineSeries.ShowLabels = True lineSeries.DataPoints.Add(New CategoricalDataPoint(8000, "Jan")) lineSeries.DataPoints.Add(New CategoricalDataPoint(8700, "Feb")) lineSeries.DataPoints.Add(New CategoricalDataPoint(8500, "Mar")) lineSeries.DataPoints.Add(New CategoricalDataPoint(8900, "Apr")) lineSeries.DataPoints.Add(New CategoricalDataPoint(8400, "May")) lineSeries.DataPoints.Add(New CategoricalDataPoint(8300, "Jun")) lineSeries.DataPoints.Add(New CategoricalDataPoint(8600, "Jul")) lineSeries.DataPoints.Add(New CategoricalDataPoint(8800, "Aug")) lineSeries.DataPoints.Add(New CategoricalDataPoint(8400, "Sep")) lineSeries.DataPoints.Add(New CategoricalDataPoint(8300, "Oct")) lineSeries.DataPoints.Add(New CategoricalDataPoint(8500, "Nov")) lineSeries.DataPoints.Add(New CategoricalDataPoint(8100, "Dec")) Me.RadChartView1.Series.Add(lineSeries) Dim lineSeries2 As New Telerik.WinControls.UI.LineSeries("2015") lineSeries2.LegendTitle = "2015" lineSeries2.ShowLabels = True lineSeries2.DataPoints.Add(New CategoricalDataPoint(5800, "Jan")) lineSeries2.DataPoints.Add(New CategoricalDataPoint(5900, "Feb")) lineSeries2.DataPoints.Add(New CategoricalDataPoint(5700, "Mar")) lineSeries2.DataPoints.Add(New CategoricalDataPoint(5500, "Apr")) lineSeries2.DataPoints.Add(New CategoricalDataPoint(5300, "May")) lineSeries2.DataPoints.Add(New CategoricalDataPoint(5600, "Jun")) lineSeries2.DataPoints.Add(New CategoricalDataPoint(5800, "Jul")) lineSeries2.DataPoints.Add(New CategoricalDataPoint(5800, "Aug")) lineSeries2.DataPoints.Add(New CategoricalDataPoint(5900, "Sep")) lineSeries2.DataPoints.Add(New CategoricalDataPoint(6100, "Oct")) lineSeries2.DataPoints.Add(New CategoricalDataPoint(7900, "Nov")) lineSeries2.DataPoints.Add(New CategoricalDataPoint(7600, "Dec")) Me.RadChartView1.Series.Add(lineSeries2) Me.RadChartView1.ShowSmartLabels = True Me.RadChartView1.ShowTitle = True Me.RadChartView1.ShowLegend = True Me.RadChartView1.LegendTitle = "Legend" Dim verticalAxis As LinearAxis = RadChartView1.Axes.[Get](Of LinearAxis)(1) verticalAxis.Minimum = 4000 verticalAxis.Maximum = 20000 verticalAxis.MajorStep = 4000 Me.RadChartView1.ShowPanZoom = True End Sub End Class
How to reproduce: Public Class Form1 Sub New() InitializeComponent() Dim barSeries As New Telerik.WinControls.UI.BarSeries("Performance", "RepresentativeName") barSeries.Name = "Q1" barSeries.LegendTitle = "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "Leg 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")) Me.RadChartView1.Series.Add(barSeries) Dim barSeries2 As New Telerik.WinControls.UI.BarSeries("Performance", "RepresentativeName") barSeries2.Name = "Q2" barSeries2.LegendTitle = "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "Le 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")) Me.RadChartView1.Series.Add(barSeries2) Me.RadChartView1.ShowTitle = True Me.RadChartView1.ShowLegend = True Me.RadChartView1.LegendTitle = "Legend" Me.RadChartView1.Size = New Size(500, 150) Me.RadChartView1.ShowPanZoom = True 'Me.SetupLineSeries() End Sub Private Sub RadButton1_Click(sender As Object, e As EventArgs) Handles RadButton1.Click Dim filePath As String = "..\..\exprotedChart2.png" Me.RadChartView1.ExportToImage(filePath, New Size(1000, 800), System.Drawing.Imaging.ImageFormat.Png) End Sub End Class Workaround: increase the size of the chart Public Class Form1 Sub New() InitializeComponent() Dim barSeries As New Telerik.WinControls.UI.BarSeries("Performance", "RepresentativeName") barSeries.Name = "Q1" barSeries.LegendTitle = "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" 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")) Me.RadChartView1.Series.Add(barSeries) Dim barSeries2 As New Telerik.WinControls.UI.BarSeries("Performance", "RepresentativeName") barSeries2.Name = "Q2" barSeries2.LegendTitle = "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" + vbCrLf + "LegendTitle1" 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")) Me.RadChartView1.Series.Add(barSeries2) Me.RadChartView1.ShowTitle = True Me.RadChartView1.ShowLegend = True Me.RadChartView1.LegendTitle = "Legend" Me.RadChartView1.Size = New Size(500, 150) Me.RadChartView1.ShowPanZoom = True 'Me.SetupLineSeries() End Sub Dim size As Size Private Sub RadButton1_Click(sender As Object, e As EventArgs) Handles RadButton1.Click AddHandler Me.RadChartView1.SizeChanged, AddressOf RadChartView1_SizeChanged size = Me.RadChartView1.Size Me.RadChartView1.Size = New Size(1000, 800) End Sub Private Sub RadChartView1_SizeChanged(sender As Object, e As EventArgs) RemoveHandler Me.RadChartView1.SizeChanged, AddressOf RadChartView1_SizeChanged Dim filePath As String = "..\..\exprotedChart2.png" Me.RadChartView1.ExportToImage(filePath, Me.RadChartView1.Size, System.Drawing.Imaging.ImageFormat.Png) Me.RadChartView1.Size = size End Sub End Class
Improve performance, when calculating the positions of Smart Labels.
To reproduce: - Add polar series and selection controller Workaround: private void RadChartView1_CreateRenderer(object sender, ChartViewCreateRendererEventArgs e) { e.Renderer = new MyPolarRenderer(e.Area as PolarArea); } class MyPolarRenderer : PolarRenderer { public MyPolarRenderer(PolarArea area) : base(area) { } public override DataPoint HitTest(int x, int y) { for (int i = 0; i < this.DrawParts.Count; i++) { DataPoint dataPoint = this.DrawParts[i].HitTest(new Point(x, y)); if (dataPoint != null) { return dataPoint; } } return base.HitTest(x, y); } protected override void Initialize() { base.Initialize(); for (int i = 0; i < this.DrawParts.Count; i++) { PolarPointSeriesDrawPart linePart = this.DrawParts[i] as PolarPointSeriesDrawPart; if (linePart != null) { this.DrawParts[i] = new MyDrawpart((PolarPointSeries)linePart.Element, this); } } } } class MyDrawpart : PolarPointSeriesDrawPart { public MyDrawpart(PolarPointSeries series, IChartRenderer renderer) : base(series, renderer) { } public override DataPoint HitTest(Point location) { if (this.Element.PointSize.Width == 0 || this.Element.PointSize.Height == 0) { return null; } for (int i = 0; i < this.Element.DataPoints.Count; i++) { RadRect slot = this.Element.DataPoints[i].LayoutSlot; float pointHalfWidth = this.Element.PointSize.Width / 2; float pointHalfHeight = this.Element.PointSize.Height / 2; RectangleF dataPointBounds = new RectangleF((float)(slot.X - pointHalfWidth), (float)(slot.Y - pointHalfHeight), this.Element.PointSize.Width, this.Element.PointSize.Height); if (dataPointBounds.Contains(location.X, location.Y)) { return this.Element.DataPoints[i]; } } return base.HitTest(location); } }
Workaround: use a custom ChartPanZoomController public class MyChartPanZoomController : ChartPanZoomController { protected override ActionResult OnMouseWheel(MouseEventArgs e) { if (!(this.Area is CartesianArea)) { return base.OnMouseWheel(e); } if ((Control.ModifierKeys & Keys.Control) == Keys.Control) { IChartView chartView = this.Area.View; double zoomWidth = chartView.ZoomWidth; if (this.PanZoomMode == ChartPanZoomMode.Horizontal || this.PanZoomMode == ChartPanZoomMode.Both) { zoomWidth += ((double)e.Delta / 1200d); } double zoomHeight = chartView.ZoomHeight; if (this.PanZoomMode == ChartPanZoomMode.Vertical || this.PanZoomMode == ChartPanZoomMode.Both) { zoomHeight += ((double)e.Delta / 1200d); } zoomWidth = this.ClampValue(zoomWidth, 1d, 100d); zoomHeight = this.ClampValue(zoomHeight, 1d, 100d); double virtualHorizontalPosition = e.X - this.Area.AreaModel.LayoutSlot.X - chartView.PlotOriginX; double plotAreaVirtualWidth = this.Area.AreaModel.LayoutSlot.Width * chartView.ZoomWidth; double relativeHorizontalPosition = virtualHorizontalPosition / plotAreaVirtualWidth; double newPlotAreaVirtualWidth = this.Area.AreaModel.LayoutSlot.Width * zoomWidth; double newPanOffsetX = (newPlotAreaVirtualWidth * relativeHorizontalPosition) - (e.X - this.Area.AreaModel.LayoutSlot.X); newPanOffsetX = this.ClampValue(newPanOffsetX, 0, this.Area.AreaModel.LayoutSlot.Width * (zoomWidth - 1d)); double virtualVerticalPosition = e.Y - this.Area.AreaModel.LayoutSlot.Y - chartView.PlotOriginY; double plotAreaVirtualHeight = this.Area.AreaModel.LayoutSlot.Height * chartView.ZoomHeight; double relativeVerticalPosition = virtualVerticalPosition / plotAreaVirtualHeight; double newPlotAreaVirtualHeight = this.Area.AreaModel.LayoutSlot.Height * zoomHeight; double newPanOffsetY = (newPlotAreaVirtualHeight * relativeVerticalPosition) - (e.Y - this.Area.AreaModel.LayoutSlot.Y); newPanOffsetY = this.ClampValue(newPanOffsetY, 0, this.Area.AreaModel.LayoutSlot.Height * (zoomHeight - 1d)); this.Area.View.Zoom(zoomWidth, zoomHeight); this.Area.View.Pan(-newPanOffsetX, -newPanOffsetY); } return Controller.Empty; } private double ClampValue(double value, double minValue, double maxValue) { return Math.Max(minValue, Math.Min(value, maxValue)); } }
To reproduce: public RadForm1() { InitializeComponent(); Random rand = new Random(); LineSeries lineSeria = new LineSeries(); lineSeria.ValueMember = "WorkingHours"; lineSeria.CategoryMember = "Date"; lineSeria.ShowLabels = true; lineSeria.PointSize = new System.Drawing.SizeF(10, 10); lineSeria.BackColor = Color.Red; LinearAxis verticalAxis2 = new LinearAxis(); verticalAxis2.AxisType = AxisType.Second; verticalAxis2.HorizontalLocation = AxisHorizontalLocation.Right ; lineSeria.VerticalAxis = verticalAxis2; DataTable table = new DataTable(); table.Columns.Add("Value", typeof(double)); table.Columns.Add("Name", typeof(string)); table.Rows.Add(rand.Next(1, 20), "John"); table.Rows.Add(rand.Next(1, 20), "Adam"); table.Rows.Add(rand.Next(1, 20), "Peter"); table.Rows.Add(rand.Next(1, 20), "Sam"); table.Rows.Add(rand.Next(1, 20), "Paul"); lineSeria.ValueMember = "Value"; lineSeria.CategoryMember = "Name"; lineSeria.DataSource = table; BarSeries barSeria = new BarSeries(); barSeria.ValueMember = "Finished"; barSeria.CategoryMember = "Date"; barSeria.ShowLabels = true; barSeria.BackColor = Color.Aqua; LinearAxis verticalAxis1 = new LinearAxis(); verticalAxis1.AxisType = AxisType.Second; verticalAxis1.HorizontalLocation = AxisHorizontalLocation.Left; barSeria.VerticalAxis = verticalAxis1; table = new DataTable(); table.Columns.Add("Value", typeof(double)); table.Columns.Add("Name", typeof(string)); table.Rows.Add(rand.Next(1, 20), "John"); table.Rows.Add(rand.Next(1, 20), "Adam"); table.Rows.Add(rand.Next(1, 20), "Peter"); table.Rows.Add(rand.Next(1, 20), "Sam"); table.Rows.Add(rand.Next(1, 20), "Paul"); barSeria.ValueMember = "Value"; barSeria.CategoryMember = "Name"; barSeria.DataSource = table; this.radChartView1.ChartElement.View.Series.Add(lineSeria); this.radChartView1.ChartElement.View.Series.Add(barSeria); this.radChartView1.ChartElement.Margin = new System.Windows.Forms.Padding(10); (this.radChartView1.ChartElement.View.Axes[0] as CategoricalAxis).LabelFitMode = Telerik.Charting.AxisLabelFitMode.MultiLine; SmartLabelsController c = new SmartLabelsController(); this.radChartView1.ChartElement.View.Controllers.Add(c); } Workaround: change the strategy: SmartLabelsController c = new SmartLabelsController(); c.Strategy = new FourPositionsLabelsStrategy(); this.radChartView1.ChartElement.View.Controllers.Add(c);
Workaround: Sub New() InitializeComponent() AddHandler Me.RadChartView1.CreateRenderer, AddressOf CreateRenderer AddHandler Me.RadChartView1.LabelFormatting, AddressOf LabelFormatting Dim barSeries As New Telerik.WinControls.UI.BarSeries("Performance", "RepresentativeName") barSeries.ShowLabels = True 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")) Me.RadChartView1.Series.Add(barSeries) Dim barSeries2 As New Telerik.WinControls.UI.BarSeries("Performance", "RepresentativeName") barSeries2.ShowLabels = True 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")) Me.RadChartView1.Series.Add(barSeries2) End Sub Private Sub LabelFormatting(sender As Object, e As Telerik.WinControls.UI.ChartViewLabelFormattingEventArgs) Dim dataPoint As CategoricalDataPoint = TryCast(e.LabelElement.DataPoint, CategoricalDataPoint) e.LabelElement.Text = "Value: " & Environment.NewLine & dataPoint.Value e.LabelElement.BackColor = Color.Yellow End Sub Private Sub CreateRenderer(sender As Object, e As ChartViewCreateRendererEventArgs) e.Renderer = New CustomCartesianRenderer(TryCast(e.Area, CartesianArea)) End Sub Public Class CustomCartesianRenderer Inherits CartesianRenderer Public Sub New(area As CartesianArea) MyBase.New(area) End Sub Protected Overrides Sub Initialize() MyBase.Initialize() For i As Integer = 0 To Me.DrawParts.Count - 1 Dim labelPart As BarLabelElementDrawPart = TryCast(Me.DrawParts(i), BarLabelElementDrawPart) If labelPart IsNot Nothing Then Me.DrawParts(i) = New CustomLabelElementDrawPart(DirectCast(labelPart.Element, BarSeries), Me) End If Next End Sub End Class Public Class CustomLabelElementDrawPart Inherits BarLabelElementDrawPart Public Sub New(owner As ChartSeries, renderer As IChartRenderer) MyBase.New(owner, renderer) End Sub Public Overrides Sub Draw() For Each dataPointElement As DataPointElement In Me.Element.Children For Each label As LabelElement In dataPointElement.Children label.ForeColor = Color.Transparent Next Next MyBase.Draw() Dim graphics As Graphics = TryCast(Me.Renderer.Surface, Graphics) Dim radGraphics As New RadGdiGraphics(graphics) Dim slot As RadRect Dim rect As Rectangle Dim stringFormat As New StringFormat() stringFormat.Alignment = StringAlignment.Center stringFormat.LineAlignment = StringAlignment.Center For Each dataPointElement As DataPointElement In Me.Element.Children For Each label As LabelElement In dataPointElement.Children label.ForeColor = Color.Transparent slot = label.GetLayoutSlot() slot = AdjustLayoutSlot(slot, label.DataPointElement) rect = ChartRenderer.ToRectangle(slot) Using brush As Brush = New SolidBrush(Color.Red) Dim drawLocation As New PointF() drawLocation.X = rect.X + label.Padding.Left drawLocation.Y = rect.Y + label.Padding.Top graphics.DrawString(label.Text, label.Font, brush, rect, stringFormat) End Using Next Next End Sub End Class
Good day,
My requierment is to have a RadChartView with a LineSeries and a RangeSeries. I add CategoricalDataPoint objects manually to the LineSeries and I manually add RangeDataPoint objects to the RangeSeries.
When I encounter NULL valued datapoints, for the LineSeries, I do the following. The NULL valued datapoints appear as gaps in the chart as expected.
Dim value As Nullable(Of Double) Dim serControl As LineSeries serControl = New LineSeries() chart.Series.Add(serControl) value = IIf(IsDBNull(dr(data.ControlParameter.ID.ToString())), New Nullable(Of Double), dr(data.ControlParameter.ID.ToString())) serControl.DataPoints.Add(New Telerik.Charting.CategoricalDataPoint(value))
However the RangeSeries do not handle the NULL valued datapoints the same. I get the following error: Nullable object must have a value.
Dim LowerBound, UpperBound As Nullable(Of Double) Dim serRange As RangeSeries serRange = New RangeSeries() chart.Series.Add(serRange) LowerBound = IIf(IsDBNull(dr("Lowerbound"), New Nullable(Of Double), dr("LowerBound")) UpperBound = IIf(IsDBNull(dr("Upperbound"), New Nullable(Of Double), dr("UpperBound")) serRange.DataPoints.Add(New Telerik.Charting.RangeDataPoint(UpperBound, LowerBound))
I need to be able to show gaps, not zero's in a RangeSeries when there are NULL values.
How can I do this?
How to reproduce: public partial class Form1 : Form { public Form1() { InitializeComponent(); this.radChartView1.ShowLegend = true; LineSeries lineSeries = new LineSeries(); lineSeries.DataPoints.Add(new CategoricalDataPoint(20, "Jan")); lineSeries.DataPoints.Add(new CategoricalDataPoint(22, "Apr")); lineSeries.DataPoints.Add(new CategoricalDataPoint(12, "Jul")); lineSeries.DataPoints.Add(new CategoricalDataPoint(19, "Oct")); this.radChartView1.Series.Add(lineSeries); LineSeries lineSeries2 = new LineSeries(); lineSeries2.DataPoints.Add(new CategoricalDataPoint(18, "Jan")); lineSeries2.DataPoints.Add(new CategoricalDataPoint(15, "Apr")); lineSeries2.DataPoints.Add(new CategoricalDataPoint(17, "Jul")); lineSeries2.DataPoints.Add(new CategoricalDataPoint(22, "Oct")); this.radChartView1.Series.Add(lineSeries2); ChartPanZoomController panZoomController = new ChartPanZoomController(); panZoomController.PanZoomMode = ChartPanZoomMode.Horizontal; radChartView1.Controllers.Add(panZoomController); } private void radButton1_Click(object sender, EventArgs e) { this.radChartView1.ExportToImage(@"..\..\image.png", this.radChartView1.Size, System.Drawing.Imaging.ImageFormat.Png); } } Workaround: use a custom export to image method public void ExportChartToImage(string filePath, Size size, ImageFormat imageFormat) { using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write)) { if (!this.radChartView1.IsLoaded) { this.radChartView1.LoadElementTree(); } Bitmap bmp = new Bitmap(size.Width, size.Height); Graphics graphics = Graphics.FromImage(bmp); graphics.Clear(Color.White); SizeF titleSize = graphics.MeasureString(this.radChartView1.Title, this.radChartView1.ChartElement.TitleElement.Font, this.Width); if (this.radChartView1.ChartElement.TitleElement.TextOrientation == Orientation.Vertical) { float swap = titleSize.Height; titleSize.Height = titleSize.Width; titleSize.Width = swap; } RadRect titleRect = new RadRect(0, 0, titleSize.Width, titleSize.Height); RadRect legendRect = new RadRect(0, 0, size.Width, size.Height); RadRect chartRect = legendRect; switch (this.radChartView1.ChartElement.TitlePosition) { case TitlePosition.Top: case TitlePosition.Bottom: titleRect.Width = size.Width; break; case TitlePosition.Right: case TitlePosition.Left: titleRect.Height = size.Height; break; } chartRect.X += this.radChartView1.View.Margin.Left; chartRect.Y += this.radChartView1.View.Margin.Top; chartRect.Width -= this.radChartView1.View.Margin.Horizontal; chartRect.Height -= this.radChartView1.View.Margin.Vertical; if (this.radChartView1.ShowTitle) { switch (this.radChartView1.ChartElement.TitlePosition) { case TitlePosition.Top: legendRect.Y += titleRect.Height; chartRect.Y += titleRect.Height; legendRect.Height -= titleRect.Height; chartRect.Height -= titleRect.Height; break; case TitlePosition.Right: titleRect.X = size.Width - this.radChartView1.ChartElement.TitleElement.Size.Width; titleRect.Height = size.Height; legendRect.Width -= titleRect.Width; chartRect.Width -= titleRect.Width; break; case TitlePosition.Bottom: titleRect.Y = size.Height - this.radChartView1.ChartElement.TitleElement.Size.Height; titleRect.Width = size.Width; legendRect.Height -= titleRect.Height; chartRect.Height -= titleRect.Height; break; case TitlePosition.Left: titleRect.Height = size.Height; legendRect.X += titleRect.Width; chartRect.X += titleRect.Width; legendRect.Width -= titleRect.Width; chartRect.Width -= titleRect.Width; break; } } if (this.radChartView1.ShowLegend) { switch (this.radChartView1.ChartElement.LegendPosition) { case LegendPosition.Right: if (this.radChartView1.ChartElement.TitlePosition == TitlePosition.Right) { legendRect.X = titleRect.X - this.radChartView1.ChartElement.LegendElement.Size.Width; } else { legendRect.X = size.Width - this.radChartView1.ChartElement.LegendElement.Size.Width; } legendRect.Width = this.radChartView1.ChartElement.LegendElement.Size.Width; chartRect.Width -= this.radChartView1.View.Margin.Right; break; case LegendPosition.Bottom: if (this.radChartView1.ChartElement.TitlePosition == TitlePosition.Bottom) { legendRect.Y = titleRect.Y - this.radChartView1.ChartElement.LegendElement.Size.Height; } else { legendRect.Y = size.Height - this.radChartView1.ChartElement.LegendElement.Size.Height; } legendRect.Height = this.radChartView1.ChartElement.LegendElement.Size.Height; chartRect.Height -= legendRect.Height; break; case LegendPosition.Left: legendRect.Width = this.radChartView1.ChartElement.LegendElement.Size.Width; chartRect.X += legendRect.Width + this.radChartView1.View.Margin.Left; chartRect.Width -= legendRect.Width + this.radChartView1.View.Margin.Left; break; case LegendPosition.Top: legendRect.Height = this.radChartView1.ChartElement.LegendElement.Size.Height; chartRect.Y += legendRect.Height; chartRect.Height -= legendRect.Height; break; case LegendPosition.Float: legendRect.Width = this.radChartView1.ChartElement.LegendElement.Size.Width; legendRect.Height = this.radChartView1.ChartElement.LegendElement.Size.Height; double xRatio = size.Width / this.Size.Width; double yRatio = size.Height / this.Size.Height; legendRect.X = (this.radChartView1.ChartElement.LegendOffset.X * xRatio) + ((this.radChartView1.ChartElement.TitlePosition == TitlePosition.Left) ? titleRect.Right : 0d); legendRect.Y = (this.radChartView1.ChartElement.LegendOffset.Y * yRatio) + ((this.radChartView1.ChartElement.TitlePosition == TitlePosition.Top) ? titleRect.Bottom : 0f); break; } } if (this.radChartView1.ShowLegend) { float xTransform = (float)legendRect.X - this.radChartView1.ChartElement.LegendElement.ControlBoundingRectangle.X + ((float)legendRect.Width - this.radChartView1.ChartElement.LegendElement.ControlBoundingRectangle.Width) / 2f; float yTransform = (float)legendRect.Y - this.radChartView1.ChartElement.LegendElement.ControlBoundingRectangle.Y + ((float)legendRect.Height - this.radChartView1.ChartElement.LegendElement.ControlBoundingRectangle.Height) / 2f; graphics.TranslateTransform(xTransform, yTransform); this.radChartView1.ChartElement.LegendElement.Paint(new RadGdiGraphics(graphics), this.radChartView1.ChartElement.LegendElement.ControlBoundingRectangle, 0f, new SizeF(1f, 1f), true); graphics.ResetTransform(); } RadGdiGraphics radGraphics = new RadGdiGraphics(graphics); if (this.radChartView1.ShowTitle) { object[] miParams = new object[] { ChartRenderer.ToRectangleF(titleRect), titleSize, this.radChartView1.ChartElement.TitleElement.TextAlignment }; radGraphics.DrawString(this.radChartView1.Title, (RectangleF)typeof(RadChartView).GetMethod("GetTitleDrawRectangle", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(this.radChartView1, miParams), this.radChartView1.ChartElement.TitleElement.Font, this.radChartView1.ChartElement.TitleElement.ForeColor, this.radChartView1.ChartElement.TitleElement.TextParams.CreateStringFormat(), this.radChartView1.ChartElement.TitleElement.TextOrientation, this.radChartView1.ChartElement.TitleElement.FlipText); } this.radChartView1.View.Layout(chartRect); IChartRenderer renderer = (IChartRenderer)typeof(ChartArea).GetProperty("Renderer", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this.radChartView1.Area);// renderer.Draw(graphics); if (imageFormat == ImageFormat.Emf || imageFormat == ImageFormat.Wmf) { Metafile metafile = new Metafile(fs, graphics.GetHdc()); using (Graphics g = Graphics.FromImage(metafile)) { g.DrawImage(bmp, Point.Empty); } metafile.Dispose(); graphics.ReleaseHdc(); } else { bmp.Save(fs, imageFormat); } this.radChartView1.View.Layout(); }
Use the attached project to reproduce. Workaround: Check for zero values.
Workaround: CartesianRenderer renderer = null; public RadForm1() { InitializeComponent(); this.radChartView1.CreateRenderer += new ChartViewCreateRendererEventHandler(radChartView1_CreateRenderer); LineSeries lineSeries = new LineSeries(); lineSeries.LegendTitle = "Line 1"; lineSeries.DataPoints.Add(new CategoricalDataPoint(20, "Jan")); lineSeries.DataPoints.Add(new CategoricalDataPoint(22, "Apr")); lineSeries.DataPoints.Add(new CategoricalDataPoint(12, "Jul")); lineSeries.DataPoints.Add(new CategoricalDataPoint(19, "Oct")); this.radChartView1.Series.Add(lineSeries); LineSeries lineSeries2 = new LineSeries(); lineSeries2.LegendTitle = "Line 2"; lineSeries2.DataPoints.Add(new CategoricalDataPoint(18, "Jan")); lineSeries2.DataPoints.Add(new CategoricalDataPoint(15, "Apr")); lineSeries2.DataPoints.Add(new CategoricalDataPoint(17, "Jul")); lineSeries2.DataPoints.Add(new CategoricalDataPoint(22, "Oct")); this.radChartView1.Series.Add(lineSeries2); this.radChartView1.ShowLegend = true; this.radChartView1.ChartElement.LegendPosition = LegendPosition.Float; this.radChartView1.ChartElement.LegendOffset = new Point(200, 95); CartesianArea area = this.radChartView1.GetArea<CartesianArea>(); area.ShowGrid = true; } private void radChartView1_CreateRenderer(object sender, ChartViewCreateRendererEventArgs e) { renderer = new CartesianRenderer(e.Area as CartesianArea); e.Renderer = renderer; } private void radButton1_Click(object sender, EventArgs e) { string filePath = @"..\..\..\exportedChart" + DateTime.Now.ToLongTimeString().Replace(":", "_") + ".png"; using (MemoryStream stream = new MemoryStream()) { ExportToImage(this.radChartView1, stream, new Size(1000 ,500), ImageFormat.Png, filePath); } Process.Start(filePath); } public void ExportToImage(RadChartView chart, Stream stream, Size size, ImageFormat imageFormat, string filePath) { if (!this.IsLoaded) { this.LoadElementTree(); } size = Telerik.WinControls.TelerikDpiHelper.ScaleSize(size, chart.ChartElement.DpiScaleFactor); Bitmap bmp = new Bitmap(size.Width, size.Height); Graphics graphics = Graphics.FromImage(bmp); graphics.Clear(Color.White); SizeF titleSize = graphics.MeasureString(chart.Title, chart.ChartElement.TitleElement.Font, this.Width); if (chart.ChartElement.TitleElement.TextOrientation == Orientation.Vertical) { float swap = titleSize.Height; titleSize.Height = titleSize.Width; titleSize.Width = swap; } RadRect titleRect = new RadRect(0, 0, titleSize.Width, titleSize.Height); RadRect legendRect = new RadRect(0, 0, size.Width, size.Height); RadRect chartRect = legendRect; switch (chart.ChartElement.TitlePosition) { case TitlePosition.Top: case TitlePosition.Bottom: titleRect.Width = size.Width; break; case TitlePosition.Right: case TitlePosition.Left: titleRect.Height = size.Height; break; } chartRect.X += chart.View.Margin.Left; chartRect.Y += chart.View.Margin.Top; chartRect.Width -= chart.View.Margin.Horizontal; chartRect.Height -= chart.View.Margin.Vertical; if (chart.ShowTitle) { switch (chart.ChartElement.TitlePosition) { case TitlePosition.Top: legendRect.Y += titleRect.Height; chartRect.Y += titleRect.Height; legendRect.Height -= titleRect.Height; chartRect.Height -= titleRect.Height; break; case TitlePosition.Right: titleRect.X = size.Width - chart.ChartElement.TitleElement.Size.Width; titleRect.Height = size.Height; legendRect.Width -= titleRect.Width; chartRect.Width -= titleRect.Width; break; case TitlePosition.Bottom: titleRect.Y = size.Height - chart.ChartElement.TitleElement.Size.Height; titleRect.Width = size.Width; legendRect.Height -= titleRect.Height; chartRect.Height -= titleRect.Height; break; case TitlePosition.Left: titleRect.Height = size.Height; legendRect.X += titleRect.Width; chartRect.X += titleRect.Width; legendRect.Width -= titleRect.Width; chartRect.Width -= titleRect.Width; break; } } chart.View.Layout(chartRect); renderer.Draw(graphics); if (chart.ShowLegend) { switch (chart.ChartElement.LegendPosition) { case LegendPosition.Right: if (chart.ChartElement.TitlePosition == TitlePosition.Right) { legendRect.X = titleRect.X - chart.ChartElement.LegendElement.Size.Width; } else { legendRect.X = size.Width - chart.ChartElement.LegendElement.Size.Width; } legendRect.Width = chart.ChartElement.LegendElement.Size.Width; chartRect.Width -= legendRect.Width; break; case LegendPosition.Bottom: if (chart.ChartElement.TitlePosition == TitlePosition.Bottom) { legendRect.Y = titleRect.Y - chart.ChartElement.LegendElement.Size.Height; } else { legendRect.Y = size.Height - chart.ChartElement.LegendElement.Size.Height; } legendRect.Height = chart.ChartElement.LegendElement.Size.Height; chartRect.Height -= legendRect.Height; break; case LegendPosition.Left: legendRect.Width = chart.ChartElement.LegendElement.Size.Width; chartRect.X += legendRect.Width; chartRect.Width -= legendRect.Width; break; case LegendPosition.Top: legendRect.Height = chart.ChartElement.LegendElement.Size.Height; chartRect.Y += legendRect.Height; chartRect.Height -= legendRect.Height; break; case LegendPosition.Float: legendRect.Width = chart.ChartElement.LegendElement.Size.Width; legendRect.Height = chart.ChartElement.LegendElement.Size.Height; double xRatio = size.Width / this.Size.Width; double yRatio = size.Height / this.Size.Height; legendRect.X = (chart.ChartElement.LegendOffset.X * xRatio) + ((chart.ChartElement.TitlePosition == TitlePosition.Left) ? titleRect.Right : 0d); legendRect.Y = (chart.ChartElement.LegendOffset.Y * yRatio) + ((chart.ChartElement.TitlePosition == TitlePosition.Top) ? titleRect.Bottom : 0f); break; } } if (chart.ShowLegend) { float xTransform = (float)legendRect.X - chart.ChartElement.LegendElement.ControlBoundingRectangle.X + ((float)legendRect.Width - chart.ChartElement.LegendElement.ControlBoundingRectangle.Width) / 2f; float yTransform = (float)legendRect.Y - chart.ChartElement.LegendElement.ControlBoundingRectangle.Y + ((float)legendRect.Height - chart.ChartElement.LegendElement.ControlBoundingRectangle.Height) / 2f; graphics.TranslateTransform(xTransform, yTransform); chart.ChartElement.LegendElement.Paint(new RadGdiGraphics(graphics), chart.ChartElement.LegendElement.ControlBoundingRectangle, 0f, new SizeF(1f, 1f), true); graphics.ResetTransform(); } RadGdiGraphics radGraphics = new RadGdiGraphics(graphics); if (chart.ShowTitle) { radGraphics.DrawString(chart.Title, GetTitleDrawRectangle(ChartRenderer.ToRectangleF(titleRect), titleSize, chart.ChartElement.TitleElement.TextAlignment), chart.ChartElement.TitleElement.Font, chart.ChartElement.TitleElement.ForeColor, chart.ChartElement.TitleElement.TextParams.CreateStringFormat(), chart.ChartElement.TitleElement.TextOrientation, chart.ChartElement.TitleElement.FlipText); } if (imageFormat == ImageFormat.Emf || imageFormat == ImageFormat.Wmf) { Metafile metafile = new Metafile(stream, graphics.GetHdc()); // file is created here using (Graphics g = Graphics.FromImage(metafile)) { g.DrawImage(bmp, Point.Empty); } metafile.Dispose(); graphics.ReleaseHdc(); } else { bmp.Save(stream, imageFormat); } chart.View.Layout(); Image img = Image.FromStream(stream); graphics.DrawImage(img, new Point(0, 0)); img.Save(filePath); } private RectangleF GetTitleDrawRectangle(RectangleF drawArea, SizeF textRect, ContentAlignment textAlignment) { switch (textAlignment) { case ContentAlignment.BottomCenter: return new RectangleF(new PointF(drawArea.X + (drawArea.Width - textRect.Width) / 2f, drawArea.Bottom - textRect.Height), textRect); case ContentAlignment.BottomLeft: return new RectangleF(new PointF(drawArea.X, drawArea.Bottom - textRect.Height), textRect); case ContentAlignment.BottomRight: return new RectangleF(new PointF(drawArea.Right - textRect.Width, drawArea.Bottom - textRect.Height), textRect); case ContentAlignment.MiddleCenter: return new RectangleF(new PointF(drawArea.X + (drawArea.Width - textRect.Width) / 2f, drawArea.Y + (drawArea.Height - textRect.Height) / 2f), textRect); case ContentAlignment.MiddleLeft: return new RectangleF(new PointF(drawArea.X, drawArea.Y + (drawArea.Height - textRect.Height) / 2f), textRect); case ContentAlignment.MiddleRight: return new RectangleF(new PointF(drawArea.Right - textRect.Width, drawArea.Y + (drawArea.Height - textRect.Height) / 2f), textRect); case ContentAlignment.TopCenter: return new RectangleF(new PointF(drawArea.X + (drawArea.Width - textRect.Width) / 2, drawArea.Y), textRect); case ContentAlignment.TopLeft: return new RectangleF(drawArea.Location, textRect); case ContentAlignment.TopRight: return new RectangleF(new PointF(drawArea.Right - textRect.Width, drawArea.Y), textRect); default: return new RectangleF(drawArea.Location, textRect); } }
To reproduce: Add stacked series with equal category that has negative values as well.
To reproduce: - Set the title and the offset: radChartView1.Title = "Test Title"; radChartView1.ShowTitle = true; radChartView1.ChartElement.TitleElement.PositionOffset = new SizeF(100, 100); - Export the chart.
Please refer to the attached sample project. Select a range from RadRangeSelector and print the chart. You will notice that the preview chart is shifted. Even if the the default margin is reduced to 0, the preview chart is not the same as the one displayed on the form.
Workaround: export the chart to a file which file can be printed: https://docs.telerik.com/devtools/winforms/controls/chartview/features/export
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);
}
}