[UPDATE]
Чтобы завершить этот вопрос, я реализовал свой график, используя следующие два метода (см. Ниже). drawCurve()
получает Canvas
и массив float
. Массив правильно заполнен (временные метки предполагаются индексом значения в массиве) и варьируется от 0,0 до 1,0. Массив отправляется на prepareWindowArray()
, который занимает часть массива из позиции windowStart
для windowSize
-значений, по кругу.
Массив, используемый GraphView и поставщиком данных (устройством Bluetooth), одинаков. Класс в середине гарантирует, что GraphView не читает данные, которые записываются устройством Bluetooth. Поскольку GraphView всегда проходит цикл по массиву и перерисовывает его на каждой итерации, он будет обновляться в соответствии с данными, записанными устройством Bluetooth, и путем установки частоты записи устройства Bluetooth на частоту обновления графика, я получаю плавный переход анимация моего сигнала.
Метод GraphView
invalidate()
вызывается Activity
, который запускает Timer
для обновления графика каждые x
миллисекунд. Частота обновления графика устанавливается динамически, так что он адаптируется к потоку данных с устройства Bluetooth (которые указывают частоту его сигнала в заголовке пакета).
Найдите полный код моего GraphView
в ответе, который я написал ниже (в разделе ответов). Если вы, ребята, найдете ошибки или способ их оптимизации, пожалуйста, дайте мне знать; это будет с благодарностью!
/**
* Read a buffer array of size greater than "windowSize" and create a window array out of it.
* A curve is then drawn from this array using "windowSize" points, from left
* to right.
* @param canvas is a Canvas object on which the curve will be drawn. Ensure the canvas is the
* later drawn object at its position or you will not see your curve.
* @param data is a float array of length > windowSize. The floats must range between 0.0 and 1.0.
* A value of 0.0 will be drawn at the bottom of the graph, while a value of 1.0 will be drawn at
* the top of the graph. The range is not tested, so you must ensure to pass proper values, or your
* graph will look terrible.
* 0.0 : draw at the bottom of the graph
* 0.5 : draw in the middle of the graph
* 1.0 : draw at the top of the graph
*/
private void drawCurve(Canvas canvas, float[] data){
// Create a reference value to determine the stepping between each points to be drawn
float incrementX = (mRightSide-mLeftSide)/(float) windowSize;
float incrementY = (mBottomSide - mTopSide);
// Prepare the array for the graph
float[] source = prepareWindowArray(data);
// Prepare the curve Path
curve = new Path();
// Move at the first point.
curve.moveTo(mLeftSide, source[0]*incrementY);
// Draw the remaining points of the curve
for(int i = 1; i < windowSize; i++){
curve.lineTo(mLeftSide + (i*incrementX), source[i] * incrementY);
}
canvas.drawPath(curve, curvePaint);
}
Метод prepareWindowArray()
, реализующий циклическое поведение массива:
/**
* Extract a window array from the data array, and reposition the windowStart
* index for next iteration
* @param data the array of data from which we get the window
* @return an array of float that represent the window
*/
private float[] prepareWindowArray(float[] data){
// Prepare the source array for the graph.
float[] source = new float[windowSize];
// Copy the window from the data array into the source array
for(int i = 0; i < windowSize; i++){
if(windowStart+i < data.length) // If the windows holds within the data array
source[i] = data[windowStart + i]; // Simply copy the value in the source array
else{ // If the window goes beyond the data array
source[i] = data[(windowStart + 1)%data.length]; // Loop at the beginning of the data array and copy from there
}
}
// Reposition the buffer index
windowStart = windowStart + windowSize;
// If the index is beyond the end of the array
if(windowStart >= data.length){
windowStart = windowStart % data.length;
}
return source;
}
[/ UPDATE]
Я создаю приложение, которое считывает данные с устройства Bluetooth с фиксированной скоростью. Каждый раз, когда у меня появляются новые данные, я хочу, чтобы они отображались на графике справа и переводили оставшуюся часть графика влево в реальном времени. В основном, как осциллограф сделал бы.
Итак, я сделал собственный вид с осью xy, заголовком и единицами измерения. Для этого я просто рисую эти вещи на холсте вида. Теперь я хочу нарисовать кривую. Мне удается нарисовать статическую кривую из уже заполненного массива, используя этот метод:
public void drawCurve(Canvas canvas){
int left = getPaddingLeft();
int bottom = getHeight()-getPaddingTop();
int middle = (bottom-10)/2 - 10;
curvePaint = new Paint();
curvePaint.setColor(Color.GREEN);
curvePaint.setStrokeWidth(1f);
curvePaint.setDither(true);
curvePaint.setStyle(Paint.Style.STROKE);
curvePaint.setStrokeJoin(Paint.Join.ROUND);
curvePaint.setStrokeCap(Paint.Cap.ROUND);
curvePaint.setPathEffect(new CornerPathEffect(10) );
curvePaint.setAntiAlias(true);
mCurve = new Path();
mCurve.moveTo(left, middle);
for(int i = 0; i < mData[0].length; i++)
mCurve.lineTo(left + ((float)mData[0][i] * 5), middle-((float)mData[1][i] * 20));
canvas.drawPath(mCurve, curvePaint);
}
Это дает мне что-то вроде этого.
На моем графике все еще есть что исправить (подось неправильно масштабируется), но это детали, которые я могу исправить позже.
Теперь я хочу изменить этот статический график (который получает нединамическую матрицу значений) на что-то динамическое, которое будет перерисовывать кривую каждые 40 мс, сдвигая старые данные влево и отображая новые данные вправо, поэтому Я мог бы визуализировать в режиме реального времени информацию, предоставленную устройством Bluetooth.
Я знаю, что уже есть какой-то графический пакет, но я вроде как схожу с этими вещами, и я бы хотел практиковать, реализуя этот график сам. Кроме того, большая часть моего класса GraphView выполнена, за исключением части кривой.
Второй вопрос, мне интересно, как мне отправить новые значения на график. Должен ли я использовать что-то вроде стека FIFO, или я могу достичь того, чего хочу, с простой матрицей двойных чисел?
Кстати, 4 поля внизу уже динамически обновляются. Ну, они как бы имитируют «динамику», они снова и снова повторяют одну и ту же двойную матрицу, на самом деле они не принимают новые значения.
Спасибо за ваше время! Если что-то неясно по моему вопросу, дайте мне знать, и я обновлю его более подробной информацией.