假设我有这个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位置值,只需将
MotionEvent
x位置与toScreenPoint()
转换的数据点x位置进行比较。toScreenPoint()
将数据点的x位置转换为MotionEvent
使用的相同坐标系(例如“屏幕空间”)。从那里,找出用户在接触时最接近的数据点是一件很简单的事情,它通过转换后的数据点x位置循环,并与MotionEvent
x位置进行比较。:)
最佳答案
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/