0

I'm creating a line chart, using XYSeries, etc. Working great, except I'm finding it impossible to get the GraphicalView.getCurrentSeriesAndPoint() within the callbacks of an onTouchLlistener. I have both and onClick and onTouch on the chart, as I need to handle other gestures as well as the data point onClicks.

When I use just an onClickListener, everything works as expected; the calls to chartView.getCurrentSeries... returns the SeriesSelection. However, once I also set an onToucheListener, everything breaks.

I started with the standard means of mixing the two, where I maintain the touch state within my onTouchListener, and then when it resolves to MotionEvent.ACTION_UP, if I determine it's just a click, I invoke performClick on the passed in view, which is chart/graphicalview, which results in null return for getCurrentSeriesAndPoint call. Here's the code; nothing special going on here:

case MotionEvent.ACTION_UP:

                        if (onClick)
                            {
                            Log.d(TAG, "actionUp onClick should be clicking, " +
                                               "and mCurrentSS: " + mCurrentSeriesSelection);
                            SeriesSelection ss = ((GraphicalView)v).getCurrentSeriesAndPoint(); //always null
                            if (ss == null)
                                {
                                Log.d(TAG, "No point clicked");
                                }
                            else
                                {
                                Log.d(TAG, "Handle overlays on point: " + ss);
                                mListener.userDidClickPoint(ss);

                                }
                            return true;
                            }...

ss is always null. I also tried the call on the reference i have to the chart/graph...view directly, and still null. Next idea was making the call during the onTouch's MotionEvent.ACTION_DOWN block, and tried it both with direct call on the view, and also with performClick on the view to see if I could grab the SS there, like this:

case MotionEvent.ACTION_DOWN:
                        onClick = true;
                        //mCurrentSeriesSelection var to hang onto the results; always              ends up null
                        mCurrentSeriesSelection = mChart.getCurrentSeriesAndPoint();
                        //this doesn't work either, the call in the onClick will also return null
                        v.performClick();
                        Log.d(TAG, "the current series selection in onTouch action down: " +
                                           mCurrentSeriesSelection);
                        break;

Now thoroughly confused, I search for some more knowledge, and come across this wonderful post, which basically involves getting your current series, and iterating over each of it's points, comparing view position coordinate (while accounting for the point size you set up on the renderer, even), which I then wrap up on a method of my own:

private SeriesDataPoint seriesPointForClickedViewWithMotionEvent(View v, MotionEvent event)
        {
        SeriesDataPoint sdp = null;
        SeriesSelection ss = null;
        Point screenCoordinate = null;
        for (int i = 0; i < mSeries.getItemCount(); i++)
            {
            Log.d(TAG, "mSeries.getX i: " + mSeries.getX(i));
            Log.d(TAG, "mSeries.getY i: " + mSeries.getY(i));
            double[] xy = mXYChart.toScreenPoint(new double[]{mSeries.getX(i), mSeries.getY(i)}, 0);

            double dx = (xy[0] - event.getX());
            double dy = (xy[1] - event.getY());
            double distance = Math.sqrt(dx * dx + dy * dy);
            if (distance <= 2 * mRenderer.getPointSize())
                {
                screenCoordinate = new Point((float) xy[0],
                                                    (float) xy[1]);
                ss = mXYChart.getSeriesAndPointForScreenCoordinate(screenCoordinate);
                sdp = new SeriesDataPoint(ss, screenCoordinate);
                break;
                }
            }
        return sdp;
        }

(where SeriesDataPoint is just a simple class I'm using to pass all the stuff I need back to the caller; ignore it) Problem with this is:

double[] xy = mXYChart.toScreenPoint(new double[]{mSeries.getX(i), mSeries.getY(i)}, 0);

crashed with NPE, even though mXYChart, and mSeries and not null and valid. Total bummer...

So, I'm out of ideas on how to accomplish what I need to do, which is simply getting the SeriesSelection corresponding clicked chart point. Thanks.

Community
  • 1
  • 1
wkhatch
  • 2,664
  • 7
  • 36
  • 45

1 Answers1

1

My error was thinking that I was referencing the same line chart that the graphical view was using, and I was not. I ended up redoing the way I instantiate the GraphicalView, by using the (Context, AbstractChart) constructor, and passing in my LineChart instance. Once that was done, the problem line:

double[] xy = mXYChart.toScreenPoint(new double[]{mSeries.getX(i), mSeries.getY(i)}, 0);

no longer crashed, and I was able to determine which series point was clicked within the onTouch handling. So, in short, you have to make sure that the LineChart you're calling that method on is in fact the one being rendered as part of constructing your GraphicalView. I know that's been mentioned elsewhere, but I didn't connect it at first, so, just reiterating here. Thanks.

wkhatch
  • 2,664
  • 7
  • 36
  • 45