android - 如何获得XYSeries X位置的屏幕X位置?

标签 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与数据点不匹配,则不会返回任何内容。
有什么想法吗?
更新:
考虑到丹的智慧,您可以使用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()将屏幕点转换为实际点时,它总是为x位置(这是我唯一真正关心的位置)提供-Infinity。我不确定是否应该将“原始”屏幕点(从MotionEvent中)或“转换”屏幕点(从toScreenPoint()中获取)传递给它,所以我尝试将两者都传递给它,以查看它将输出什么。
我做错什么了吗?如果没有,有什么想法吗?
更新3:
我认为我们(或者更确切地说……i)可能是想得太多了。MotionEvent提供的点实际上不需要转换;它提供的坐标已经是正确的类型,“屏幕空间”。需要翻译的是数据点坐标;它们在“图表空间”中,为了将它们与“屏幕空间”进行比较,您必须将它们翻译为thully。
请考虑以下代码:
@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坐标与数据点坐标进行比较。
我不会费心发布这段代码的冗长输出,因为它并不真正重要。重要的是要意识到,如果我在“8pm”x轴(其内部数据点值为20[12+8=20])的任何垂直方向触摸屏幕,我在MotionEvent中接收到的OnTouchListener坐标告诉我在大约420.0(+/-20)的x位置触摸。现在,如果我查看所有翻译的“screenpoint”值,我会发现一个大约是420.0的值--“8pm”的值!
简而言之,要将用户的触摸转换为数据点x位置值,只需将MotionEventx位置与toScreenPoint()转换的数据点x位置进行比较。toScreenPoint()将数据点的x位置转换为MotionEvent使用的相同坐标系(例如“屏幕空间”)。从那里,找出用户在接触时最接近的数据点是一件很简单的事情,它通过转换后的数据点x位置循环,并与MotionEventx位置进行比较。:)

最佳答案

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)

关于android - 如何获得XYSeries X位置的屏幕X位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15655391/

相关文章:

android - 使用多个系列的不同颜色条

android - 如何使用 achartengine 将条形图的 y 轴标签椭圆化

java - 如何在android项目上运行java类?

android - 用于 Android 4.4 屏幕录制的 API?

android - 在旋转时保存 DialogFragment 的变量

android - 将字符串数据转换为双列表

android - 根据android中图表引擎饼图中屏幕大小的标签文本大小

android - 带有半透明状态栏的全屏 DialogFragment

android - SMS 的垃圾邮件防护算法

android - achartengine 散点图点大小