1

I created a custom Candlestick chart inherited from System.Windows.Forms.DataVisualization.Charting.Chart. I have problems to retrieve the X and Y values of each DataPoint when mouse is over the area occupied by a Candlestick. I tried the HitTest Method but it works only if mouse is over the Point. Hope this screen helps:enter image description here

This is the whole code of my custom chart:

public class MyChart : Chart
    {
        const int defaultZoomLevel = 2;

        // Amount of Candles on the Range after zooming in/out
        private int[] zoomLevels = new int[6] { 1500, 750, 450, 230, 120, 50 }; 

        // Amount of Candles for the Chart Interval
        private int[] intervalLevels = new int[6] { 100, 50, 20, 15, 10, 5 };


        private int currentZoomLevel = defaultZoomLevel;

        // List of Candles to show on the Chart--- Candle is a struct with the following properties: Open,Close,High,Low,Time
        List<Candle> Candles;


        // This method is called by another Class that request a new Chart
        public void Initialize()
        {

            // Reset Current Zoom Level to default.
            currentZoomLevel = defaultZoomLevel;

            // Initialize Chart
            InitializeChart();

            this.ChartAreas[0].AxisX.ScaleView.Zoom(0, (zoomLevels[2] / 4));

            this.ChartAreas[0].AxisX.ScaleView.Position = this.ChartAreas[0].AxisX.Maximum - (zoomLevels[defaultZoomLevel] / 4);

            ScaleAxisY((int)this.ChartAreas[0].AxisX.ScaleView.ViewMinimum, (int)this.ChartAreas[0].AxisX.ScaleView.ViewMaximum);

        }

        private void ScaleAxisY(int start, int end)
        {
            double[] tempHighs = this.Series[0].Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[0]).ToArray();
            double[] tempLows = this.Series[0].Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[1]).ToArray();
            double ymin = (tempHighs.Length > 0) ? tempLows.Min() : this.Series[0].Points[this.Series[0].Points.Count - 1].YValues[0];
            double ymax = (tempLows.Length > 0) ? tempHighs.Max() : this.Series[0].Points[this.Series[0].Points.Count - 1].YValues[1];

            this.ChartAreas[0].AxisY.ScaleView.Position = ymin;
            this.ChartAreas[0].AxisY.ScaleView.Size = (ymax - this.ChartAreas[0].AxisY.ScaleView.Position);

            Update();

        }

        private void InitializeChart()
        {
            this.ChartAreas.Clear();
            this.Series.Clear();

            this.ChartAreas.Add(new ChartArea());

            this.Series.Add(new Series("candles"));

            //  PROPERTIES
            this.Series[0].ChartType = SeriesChartType.Candlestick;
            this.Series[0].Color = Color.Green;
            this.Series[0].XValueType = ChartValueType.DateTime;
            this.Series[0].IsXValueIndexed = true;
            this.Series[0].YValuesPerPoint = 4;
            this.Series[0].CustomProperties = "MaxPixelPointWidth=10,PriceDownColor=Red, PriceUpColor=Green"; ;
            this.Series[0].ChartType = SeriesChartType.Candlestick;

            //  POPULATE CHART
            // The first Candle is the latest one so I'm adding them to chart in reverse order.
            for (int i = Candles.Count - 1; i >= 0; i--)
            {
                var item = Candles[i];
                this.Series[0].Points.AddXY(item.Time.ToOADate(), item.High, item.Low, item.Open, item.Close);
            }


            var minValue = this.Series[0].Points.Min(x => x.YValues[0]);
            var maxValue = this.Series[0].Points.Max(x => x.YValues[1]);


            this.ChartAreas[0].AxisY.Minimum = minValue;
            this.ChartAreas[0].AxisY.Maximum = maxValue;

            this.ChartAreas[0].CursorX.AutoScroll = true;
            this.ChartAreas[0].AxisY.ScrollBar.Enabled = false;

            this.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
            this.ChartAreas[0].AxisX.ScaleView.SizeType = DateTimeIntervalType.Auto;

            this.ChartAreas[0].AxisX.LabelStyle.Format = "d MMM yyyy HH:mm";
            this.ChartAreas[0].AxisX.MajorGrid.Enabled = false;
            this.ChartAreas[0].AxisY.MajorGrid.Enabled = false;

            this.ChartAreas[0].AxisX.Interval = intervalLevels[defaultZoomLevel];



            ChartAreas[0].RecalculateAxesScale();
        }
    }

I've tried PixelPositionToValue on X-Axis to get the DateTime value but it gives me the point Index rather than a DateTime value and it's not even correct.

I'm sure there are some errors on my code because the same method works when used to get the Y-Axis value.

I had a similar problem retrieving the PixelPosition on the X-Axis using a DateTime value (AxisX.ValueToPixelPosition) but I found a solution.

So how can I get X and Y values of a DataPoint when mouse is over the whole candle area?

Any tips will be very appreciated!

Note: I also have methods to scroll and zoom the chart and scale the Y-axis. Maybe they also need some changes.

  • The general ways to find a point are shown [here](https://stackoverflow.com/questions/33899354/get-y-value-of-series-from-the-x-cursor-position-where-a-chartarea-is-clicked-on/33905483#33905483). Note that by setting the x-axis to indexed you pretty much give up on the values and make life really hard on yourself. Better to not do that and add some more effort to find proper scaling.. – TaW Dec 30 '17 at 18:35
  • Thanks @TaW , I will take a look soon – Fabrizio402 Dec 31 '17 at 20:16

0 Answers0