[AKTUALIZACJA] Podsumowując to pytanie, zaimplementowałem mój wykres przy użyciu dwóch metod (patrz poniżej). drawCurve()
otrzymuje Canvas
i tablicę z float
. Tablica jest poprawnie wypełniona (znaczniki czasu są przyjmowane przez indeks wartości w tablicy) i zmienia się od 0,0 do 1,0. Tablica jest wysyłana do prepareWindowArray()
, która pobiera kawałek tablicy od pozycji windowStart
dla wartości windowSize
, w sposób okrągły.Niestandardowy wykres dynamiczny w systemie Android
Tablica używana przez GraphView i przez dostawcę danych (urządzenie Bluetooth) jest taka sama. Klasa w środku zapewnia, że GraphView nie odczytuje danych zapisywanych przez urządzenie Bluetooth. Ponieważ GraphView zawsze przechodzi przez tablicę i przerysowuje ją w każdej iteracji, aktualizuje się zgodnie z danymi zapisanymi przez urządzenie Bluetooth, a wymuszając częstotliwość zapisu urządzenia Bluetooth na częstotliwości odświeżania wykresu, uzyskuję gładką animacja mojego sygnału.
GraphView
„s invalidate()
metoda jest wywoływana przez Activity
, które poruszają się Timer
odświeżyć wykres w każdych x
milisekund. Częstotliwość odświeżania wykresu jest ustawiana dynamicznie, dzięki czemu dostosowuje się do przepływu danych z urządzenia Bluetooth (które określa częstotliwość sygnału w nagłówku jego pakietu).
Znajdź pełny kod mojej GraphView
w odpowiedzi, którą napisałem poniżej (w sekcji odpowiedzi). Jeśli napotkasz błędy lub sposób na zoptymalizowanie, daj mi znać; Byłoby to bardzo docenione!
/**
* 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);
}
Sposób prepareWindowArray()
stosującego okrągły zachowanie tablicy:
/**
* 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;
}
[/ Aktualizacja]
ja co aplikację, że dane są odczytywane z urządzeniami Bluetooth stała stawka. Za każdym razem, gdy mam nowe dane, chcę je nanieść na wykres po prawej stronie, a resztę wykresu przesunąć w lewo w czasie rzeczywistym. Zasadniczo, jak zrobiłby to oscyloskop.
Więc zrobiłem niestandardowy widok, z osi XY tytuł i jednostek. Aby to zrobić, po prostu rysuję te elementy w obszarze roboczym Widok. Teraz chcę narysować krzywą. Udało mi się narysować krzywą statyczną z już wypełnionej tablicy przy użyciu tej metody:
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);
}
Daje mi coś takiego.
Są jeszcze rzeczy do montażu na moim wykresie (sub-oś nie są prawidłowo skalowania), ale są to dane można naprawić później.
Teraz chcę zmienić ten statyczny wykres (który otrzymuje nie-dynamiczną matrycę wartości) z czymś dynamicznym, który będzie odrysowywał krzywą co 40 ms, przesuwając stare dane po lewej stronie i kreśląc nowe dane po prawej stronie, dzięki czemu mogłem wizualizować w czasie rzeczywistym informacje dostarczane przez urządzenie Bluetooth.
Wiem, że istnieje jakiś pakiet graficzny, który już istnieje, ale mam trochę noob z tych rzeczy i chciałbym Practice poprzez wdrożenie tego wykresu siebie.Poza tym większość mojej klasy GraphView została wykonana, z wyjątkiem części krzywej.
Drugie pytanie, zastanawiam się, w jaki sposób wysłać nowe wartości do wykresu. Czy powinienem użyć czegoś podobnego do stosu FIFO, czy mogę osiągnąć to, co chcę, dzięki prostej macierzy podwójnej?
Na marginesie, 4 pola na dole są już dynamicznie aktualizowane. Cóż, są one w pewnym sensie fałszowaniem "dynamiki", powtarzają raz po raz tę samą podwójną matrycę, w rzeczywistości nie przyjmują nowych wartości.
Dziękujemy za poświęcony czas! Jeśli coś nie jest jasne na temat mojego pytania, daj mi znać, a zaktualizuję je, podając więcej szczegółów.
Czy możesz podać link do wszystkich projektów? to wygląda bardzo interesująco! –