{"id":2943,"date":"2025-05-09T08:05:36","date_gmt":"2025-05-09T08:05:36","guid":{"rendered":"https:\/\/mindfusion.eu\/blog\/?p=2943"},"modified":"2025-05-09T08:17:08","modified_gmt":"2025-05-09T08:17:08","slug":"add-custom-series-graphics-to-area-chart","status":"publish","type":"post","link":"https:\/\/mindfusion.dev\/blog\/add-custom-series-graphics-to-area-chart\/","title":{"rendered":"Add custom series graphics to area chart"},"content":{"rendered":"\n<p>This post shows how to add custom graphics to a chart by inheriting the SeriesRenderer class. We&#8217;ll use it to show marker lines on top of an area chart, which could be used to emphasize important values (e.g. dates on a timeline).<\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2025\/05\/chart_markers.png\"><img loading=\"lazy\" decoding=\"async\" width=\"464\" height=\"312\" src=\"https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2025\/05\/chart_markers.png\" alt=\"\" class=\"wp-image-2944\" srcset=\"https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2025\/05\/chart_markers.png 464w, https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2025\/05\/chart_markers-300x202.png 300w, https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2025\/05\/chart_markers-446x300.png 446w\" sizes=\"auto, (max-width: 464px) 100vw, 464px\" \/><\/a><\/figure>\n\n\n\n<!--more-->\n\n\n\n<p>Marker lines can be drawn by overriding Renderer2D.Draw method:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class MarkerLineRenderer : Renderer2D\n{\n    public MarkerLineRenderer(SimpleSeries series) :\n        base(new ObservableCollection&lt;Series&gt; { series })\n    {\n    }\n\n    protected override void Draw(RenderContext context)\n    {\n        var series = Series&#91;0];\n        using (var pen = new Pen(Color.Red, 2)\n            { DashStyle = System.Drawing.Drawing2D.DashStyle.Dot })\n        {\n            for (int i = 0; i &lt; series.Size; i++)\n            {\n                double x = series.GetValue(i, 0);\n                var point = GetPixel(\n                    x, context.XAxis,\n                    0, context.YAxis, context.Component);\n                context.Graphics.DrawLine(\n                    pen, point.X, 0,\n                    point.X, (float)context.Component.ActualHeight);\n            }\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>We will provide marker coordinates by populating a SimpleSeries instance:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>var markerCoords = new SimpleSeries(\n    new double&#91;] { 5, 20, 23 }, null);<\/code><\/pre>\n\n\n\n<p>and add the new graphics on top of area chart ones:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>areaChart.Plot.SeriesRenderers.Add(\n    new MarkerLineRenderer(markerCoords));<\/code><\/pre>\n\n\n\n<p>By changing DrawLines calls above with DrawImage, you could render icons on top of the chart instead. Alternatively, draw custom geometries by calling DrawPath method.<\/p>\n\n\n\n<p>Similar approach could be used to draw crosshairs at mouse position:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class CrossHairsRenderer : Renderer2D\n{\n    public CrossHairsRenderer(\n        Chart control, ObservableCollection&lt;Series&gt; series) : base(series)\n    {\n        this.control = control;\n    }\n\n    protected override void Draw(RenderContext context)\n    {\n        var chartPos = control.PointToClient(Cursor.Position);\n        var plotPos = context.Component.RootToLocal(\n            new PointD(chartPos.X, chartPos.Y));\n        using (var pen = new Pen(Color.Black, 2)\n            { DashStyle = System.Drawing.Drawing2D.DashStyle.Dot })\n        {\n            context.Graphics.DrawLine(\n                pen, (int)plotPos.X, 0,\n                (int)plotPos.X, (int)context.Component.ActualHeight);\n            context.Graphics.DrawLine(\n                pen, 0, (int)plotPos.Y,\n                (int)context.Component.ActualWidth, (int)plotPos.Y);\n        }\n    }\n\n    Chart control;\n}<\/code><\/pre>\n\n\n\n<p>That would also require repainting the chart from MouseMove event handler:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>areaChart.Plot.SeriesRenderers.Add(\n    new CrossHairsRenderer(areaChart, areaChart.Series));\nareaChart.MouseMove += OnChartMouseMove;\n\nvoid OnChartMouseMove(object? sender, MouseEventArgs e)\n{\n    areaChart.Invalidate();\n}\n<\/code><\/pre>\n\n\n\n<p>Crosshairs above do not access chart data and could be implemented as a custom Charting.Component object instead, overlaying it on top of the plot in chart&#8217;s layout. However the SeriesRender allows for easier integration with the plot, and for possible extensions to draw nearby values or coordinates from the series at the mouse location.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2025\/05\/chart_crosshairs.png\"><img loading=\"lazy\" decoding=\"async\" width=\"464\" height=\"312\" src=\"https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2025\/05\/chart_crosshairs.png\" alt=\"\" class=\"wp-image-2945\" srcset=\"https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2025\/05\/chart_crosshairs.png 464w, https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2025\/05\/chart_crosshairs-300x202.png 300w, https:\/\/mindfusion.dev\/blog\/wp-content\/uploads\/2025\/05\/chart_crosshairs-446x300.png 446w\" sizes=\"auto, (max-width: 464px) 100vw, 464px\" \/><\/a><\/figure>\n\n\n\n<p>And here&#8217;s a complete sample projects that shows both custom renderers together:<br><a href=\"https:\/\/mindfusion.dev\/_samples\/ChartCrossHairs.zip\">https:\/\/mindfusion.dev\/_samples\/ChartCrossHairs.zip<\/a><\/p>\n\n\n\n<p>Sample code above demonstrates MindFusion.Charting library for .NET Windows Forms, however we provide same API for Java, JavaScript and other .NET platforms such as Blazor and MAUI.<\/p>\n\n\n\n<p>Enjoy!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post shows how to add custom graphics to a chart by inheriting the SeriesRenderer class. We&#8217;ll use it to show marker lines on top of an area chart, which could be used to emphasize important values (e.g. dates on &hellip; <a href=\"https:\/\/mindfusion.dev\/blog\/add-custom-series-graphics-to-area-chart\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[61,74],"tags":[70,69,29],"class_list":["post-2943","post","type-post","status-publish","format-standard","hentry","category-charting-2","category-sample-code","tag-chart","tag-control","tag-winforms"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p3RlKs-Lt","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/2943","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/comments?post=2943"}],"version-history":[{"count":6,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/2943\/revisions"}],"predecessor-version":[{"id":2953,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/posts\/2943\/revisions\/2953"}],"wp:attachment":[{"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/media?parent=2943"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/categories?post=2943"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mindfusion.dev\/blog\/wp-json\/wp\/v2\/tags?post=2943"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}