3

假设我有这个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的智慧,可以通过方法得到给定屏幕x位置的“图表空间”x位置toScreenPoint(),如下:

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.)

所以现在百万美元的问题变成getXPositionForIndex()了,ACE 中是否已经有一种方法,或者是否有办法使用现有方法编写一个方法?此方法将获取 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(),它总是给我-Infinityx 位置(这是我真正关心的唯一一个)。我不确定我是否应该将“原始”屏幕点(来自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坐标与数据点坐标进行比较。

I won't bother posting the long verbose output from this code as it's not really important. What is important is to realize if I touch the screen anywhere vertically around the "8 PM" x-axis (which has an internal data point value of 20 [12 + 8 = 20]), the MotionEvent coordinate I receive in my OnTouchListener tells me I touched at around x-position 420.0 (+/- 20 or so). Now if I look thru all the translated "screenPoint" values, I find one that is is around 420.0 -- the "8 PM" one!

简而言之,要将用户的触摸转换为数据点 x 位置值,您只需将MotionEventx 位置与转换后的toScreenPoint()数据点 x 位置进行比较。将toScreenPoint()数据点的 x 位置转换到使用的相同坐标系MotionEvent(例如“屏幕空间”)。从那里开始,找出用户在触摸时最接近哪个数据点是一件简单的事情,即循环遍历转换后的数据点 x 位置并与 x 位置进行比较MotionEvent。:)

4

1 回答 1

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)
于 2013-03-27T09:42:54.777 回答