如何获得XYSeries x-position的屏幕x位置?

时间:2013-03-27 09:25:24

标签: android achartengine

假设我有XYSeries

XYSeries temps = new XYSeries("Temperature");
temps.add(0, 43);
temps.add(1, 42);
temps.add(2, 40);
temps.add(3, 38);
temps.add(4, 35);
temps.add(5, 35);
temps.add(6, 34);
temps.add(7, 33);
temps.add(8, 32);
temps.add(9, 32);

如果渲染,这将绘制10小时内的温度图。

如何获取本系列中每个数据点的屏幕x位置?换句话说,我如何找出第6个数据点在屏幕上的位置?

我要做的是确定哪个数据点最接近 - 在x轴上 - 到用户触摸屏幕的位置,以便显示数据点的详细信息。

XYChart.getSeriesAndPointForScreenCoordinate()除了用户必须直接触摸一条线以外,它们应该能够在该数据点的x轴上垂直触摸任何地方。

我认为这只是简单地将图表空间转换为屏幕空间(反之亦然),但我还没有看到Javadoc中只采用x位置的任何方法;它们都需要x和y,如果y与数据点不匹配,则不返回任何内容。

有什么想法吗?

更新

考虑到Dan的智慧,您可以使用toScreenPoint()方法获取给定屏幕x位置的“图表空间”x位置,如下所示:

double[] chartPoint = chart.toScreenPoint(new double[] {event.getX(), event.getY()}, 2);
// double[0] == 4935.436905570652

然而,现在问题是采用这个坐标并找到它最接近的数据点。如果有办法获得给定XYSeries索引/数据点的“图表空间”x位置,我可以自己手动搜索最近的数据点:

// Build a list of the data points' chart space x-positions
double[] dataPointPositions = new double[temps.getItemCount()];
for(int index = 0; index < dataPointPositions.length; index++)
{
    dataPointPositions[index] = getXPositionForIndex(index, scale);
}

// (Go thru the list of data point positions, comparing them to the
// value taken from toScreenPoint() to find which one is closest.)

现在百万美元的问题变成了,ACE中是否已经存在 getXPositionForIndex() 方法,或者有没有办法使用现有方法编写一个?此方法将获取XYSeries数据点的索引(可能还有缩放),并返回该数据点的“图表空间”x位置。 这就是我被困住的地方。

整个想法是触摸屏幕并找出用户最接近的十个(在这种情况下)数据点中的哪一个。

更新2

我更新了我的代码只是为了看看toRealPoint()会返回什么。这是我的OnTouchListener;你可以看到我输出一些不同的值只是为了看看我得到了什么:

@Override
public boolean onTouch(View view, MotionEvent event)
{
    Log.i(TAG, "onTouch()");
    Log.i(TAG, "event.x = " + event.getX() + ", event.y = " + event.getY());

    double[] screenPoints = chart.toScreenPoint(new double[] {event.getX(), event.getY()}, 0);
    Log.i(TAG, "Screen points: " + event.getX() + " = " + screenPoints[0] + ", " + event.getY() + " = " + screenPoints[1]);

    double[] realPoints1 = chart.toRealPoint(event.getX(), event.getY());
    Log.i(TAG, "Real points #1: " + event.getX() + " = " + realPoints1[0] + ", " + event.getY() + " = " + realPoints1[1]);

    double[] realPoints2 = chart.toRealPoint((float)screenPoints[0], (float)screenPoints[1]);
    Log.i(TAG, "Real points #2: " + screenPoints[0] + " = " + realPoints2[0] + ", " + screenPoints[1] + " = " + realPoints2[1]);

    return true;
}

不幸的是,我回来的数字并不乐观:

03-27 17:10:18.277: I/MainActivity(1149): onTouch()
03-27 17:10:18.277: I/MainActivity(1149): event.x = 98.19905, event.y = 259.41077
03-27 17:10:18.277: I/MainActivity(1149): Screen points: 98.19905 = 2049.3714971127715, 259.41077 = -Infinity
03-27 17:10:18.287: I/MainActivity(1149): Real points #1: 98.19905 = -Infinity, 259.41077 = 44.807568573847
03-27 17:10:18.297: I/MainActivity(1149): Real points #2: 2049.3714971127715 = -Infinity, -Infinity = Infinity

当尝试使用toRealPoint()将屏幕点转换为真实点时,它总是给我-Infinity x位置(这是我唯一真正关心的位置)。我不确定我是否应该通过“原始”屏幕点(来自MotionEvent)或“转换”屏幕点(取自toScreenPoint()),所以我尝试了看看它会输出什么。

我做错了吗?如果没有,任何想法?

更新3

我认为我们(或者更确切地说...... )可能过度思考过这种方式。 MotionEvent提供的观点实际上不需要翻译;它提供的坐标已经是正确的类型,“屏幕空间”。 需要翻译的是数据点坐标;它们位于“图表空间”中,为了将它们与“屏幕空间”进行比较,您必须对它们进行翻译。

请考虑以下代码:

@Override
public boolean onTouch(View view, MotionEvent event)
{
    Log.i(TAG, "onTouch()");
    Log.i(TAG, "event.x = " + event.getX() + ", event.y = " + event.getY());

    for(int i = 0; i < tempSeries.getItemCount(); i++)
    {
        double x = tempSeries.getX(i);
        double y = tempSeries.getY(i);
        double[] screenPoint = chart.toScreenPoint(new double[] { x, y }, 0);

        Log.i(TAG, x + "," + y + " = " + screenPoint[0] + "," + screenPoint[1]);
    }

    return true;
}

当用户触摸屏幕时,我在这里所做的只是输出MotionEvent坐标,然后我循环到XYSeries中的每个数据点。我打印出原始点(范围从0.0到23.0,因为我总共有24个数据点)。我还使用toScreenPoint()方法打印出翻译的“屏幕空间”点。这允许将MotionEvent坐标与数据点坐标进行比较。

我不打算从这段代码中发布冗长的详细输出,因为它并不重要。重要的是要知道如果我在“8 PM”x轴(内部数据点值为20 [12 + 8 = 20])的垂直位置触摸屏幕,我收到的MotionEvent坐标在我的OnTouchListener告诉我,我在x-position 420.0(+/- 20左右)附近触及。现在,如果我通过所有翻译的“screenPoint”值查看,我会发现一个大约是420.0 - 即“8 PM”一个!

简而言之,要将用户的触摸转换为数据点x位置值,您只需将MotionEvent x位置与toScreenPoint() - 已翻译的数据点x位置进行比较。 toScreenPoint()将数据点的x位置转换为MotionEvent使用的相同坐标系(例如“屏幕空间”)。从那里,确定用户在触摸时最接近哪个数据点是一个微不足道的问题,即通过翻译的数据点x位置循环并与MotionEvent x位置进行比较。 :)

1 个答案:

答案 0 :(得分:3)

XYChart类有这样一种方法:

public double[] toScreenPoint(double[] realPoint, int scale)

但是,为了使用它,您将不得不放弃用于创建GraphicalView实例的方式。

例如,这个:

GraphicalView view = ChartFactory.getLineChartView(context, dataset, renderer);

将成为这个:

XYChart chart = new LineChart(dataset, renderer);
GraphicalView view = new GraphicalView(context, chart);

这样做的好处是您将引用chart实例,因此您可以调用我提到的方法。

更新:我认为更新的问题是寻找反向方法,将屏幕点转换为真实点。您可以在XYChart

中使用此方法
public double[] toRealPoint(float screenX, float screenY, int scale)