1

I am using MPAndroidChart for displaying a line chart for my application. What I already have is a double tap listener for the whole chart.

Is there any way to obtain double tap listener control for an individual point in line chart? My best guess is to directly obtain the View object of the point and implement a gesture listener for the same. If that is plausible, how can I achieve that?

If this is not possible using MPAndroidChart, is there any other library that might help me with this?

Philipp Jahoda
  • 50,880
  • 24
  • 180
  • 187
androidnoob
  • 345
  • 2
  • 17

3 Answers3

4

Your solution would involve creating a class that implements OnChartGestureListener

You can immediately see there is a method:

void onChartDoubleTapped(android.view.MotionEvent me);

You would have to implement this method with the functionality you want. It would probably involve getting the raw pixel touch points from the MotionEvent and converting them to x and y values on the chart. There is instructions on how to do that in this answer and in the code below:

@Override
public void onChartDoubleTapped(MotionEvent me) {
    float tappedX = me.getX();
    float tappedY = me.getY();
    MPPointD point = mChart.getTransformer(YAxis.AxisDependency.LEFT).getValuesByTouchPoint(tappedX, tappedY);
    Log.d(TAG, "tapped at: " + point.x + "," + point.y);
}

Further examples of a custom OnChartGestureListener are inside the example project here

David Rawson
  • 20,912
  • 7
  • 88
  • 124
2

David Rawson's answer is just perfect and answers the question leaving no stones unturned. However, for my situation, I found the answer by firegloves more useful. I actually get the Entry object using firegloves' solution to obtain values from. Following is the code for what solved my problem but please do note that this solution is hacky and is not advised until absolutely necessary. If you want a clean solution, David Rawson's answer already covers that.

mChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
        @Override
        public void onValueSelected(Entry e, Highlight h) {
            final long selectionTime = System.currentTimeMillis();
            final Highlight copyHighlight = h;
            final Entry copyEntry = e;
            final boolean[] isTapped = {false};
            mChart.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    if (!isTapped[0]) {
                        final long doubleTapTime = System.currentTimeMillis();
                        if (doubleTapTime - selectionTime < 300) {
                            if ((motionEvent.getX() <= copyHighlight.getDrawX() + 50
                                    && motionEvent.getX() >= copyHighlight.getDrawX() - 50)
                                    && (motionEvent.getY() <= copyHighlight.getDrawY() + 50
                                    && motionEvent.getY() >= motionEvent.getY() - 50)) {
                                if (copyEntry.getX() == 1.0f && copyEntry.getY() == 1.0f) {
                                    Toast.makeText(MainActivity.this, "1,1", Toast.LENGTH_SHORT).show();
                                } else if (copyEntry.getX() == 2.0f && copyEntry.getY() == 2.0f) {
                                    Toast.makeText(MainActivity.this, "2,2", Toast.LENGTH_SHORT).show();
                                } else if (copyEntry.getX() == 3.0f && copyEntry.getY() == 3.0f) {
                                    Toast.makeText(MainActivity.this, "3,3", Toast.LENGTH_SHORT).show();
                                }
                            }
                        }
                    }
                    isTapped[0] = true;
                    return false;
                }
            });
        }

        @Override
        public void onNothingSelected() {

        }
    });

The code snippet above let me work with the Entry object which was associated with the point that was double tapped. Also, I have set a range of 100 pixels while the point was double tapped for the convenience of fat-finger tapping.

I'd love to know if there is a clean solution for double tapping a value while obtaining its Entry data.

Community
  • 1
  • 1
androidnoob
  • 345
  • 2
  • 17
1

Deeping into LineChartRenderer I think it's not possible because graph rendering is reached drawing directly on Canvas like follows:

canvas.drawPath(mCirclePathBuffer, mRenderPaint);

You could try to print all your graph children to check if I'm wrong, something like:

int size =lineChart.getChildCount();
for (int i=0; i<size; i++) {
    View v = lineChart.getChildAt(i);
    Log.i("### LINE", "### INSTANCE OF " + v.getClass());
}

If there are children views they must be accessible it this manner.

Otherwise you could try to intercept double tap on your entire LineGraph, then you could try to check if tap position correspond to a mapped position but I think you must do the entire work on your own.

Another options could be to implement OnChartValueSelectedListener and emulate double tap with a timer mechanism.

I don't think there is a library that supports this functionality.

Let me know if you find a solution please

firegloves
  • 5,581
  • 2
  • 29
  • 50