假设我有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位置进行比较。 :)
答案 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)