[MISE À JOUR] Pour conclure cette question, j'ai implémenté mon graphique en utilisant les deux méthodes suivantes (voir ci-dessous). drawCurve()
reçoit un Canvas
et un tableau de float
. Le tableau est correctement rempli (les horodatages sont pris en charge par l'index de valeur dans le tableau) et varie de 0,0 à 1,0. Le tableau est envoyé à prepareWindowArray()
qui prend un morceau du tableau de la position windowStart
pour windowSize
-values, d'une manière circulaire.Graphique dynamique personnalisé sous Android
Le tableau utilisé par GraphView et par le fournisseur de données (un périphérique Bluetooth) est le même. Une classe au centre garantit que GraphView ne lit pas les données écrites par le périphérique Bluetooth. Comme le GraphView boucle toujours à travers le tableau et le redessine à chaque itération, il se met à jour en fonction des données écrites par le périphérique Bluetooth, et en forçant la fréquence d'écriture du périphérique Bluetooth à la fréquence de rafraîchissement du Graph, j'obtiens un animation de mon signal.
La méthode de invalidate()
GraphView
est appelé par le Activity
, qui courent un Timer
pour actualiser le graphique à toutes x
millisecondes. La fréquence à laquelle le graphique est actualisé est définie dynamiquement, de sorte qu'il s'adapte au flux de données du périphérique Bluetooth (qui spécifie la fréquence de son signal dans l'en-tête de son paquet).
Trouvez le code complet de mon GraphView
dans la réponse que j'ai écrite ci-dessous (dans la section réponse). Si vous trouvez des erreurs ou si vous voulez l'optimiser, faites-le moi savoir. Ce serait vivement apprécié!
/**
* 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);
}
Procédé prepareWindowArray()
qui mettent en oeuvre le comportement circulaire de la matrice:
/**
* 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]
je fais une application qui lire des données à partir d'un dispositif Bluetooth à un taux fixe. Chaque fois que j'ai de nouvelles données, je veux qu'elles soient tracées sur le graphique à droite, et traduire le reste du graphique vers la gauche en temps réel. Fondamentalement, comme un oscilloscope ferait l'affaire. J'ai donc fait une vue personnalisée, avec un axe xy, un titre et des unités. Pour ce faire, je dessine simplement ces choses sur le canevas View. Maintenant, je veux dessiner la courbe. Je parviens à dessiner une courbe statique d'un tableau déjà rempli en utilisant cette méthode:
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);
}
Il me donne quelque chose comme ça.
Il y a encore des choses à fixer sur mon graphique (les sous-axe ne sont pas correctement mise à l'échelle), mais ce sont des détails que je peux régler plus tard. Maintenant, je veux changer ce graphique statique (qui reçoit une matrice de valeurs non dynamique) avec quelque chose de dynamique qui redessinerait la courbe toutes les 40ms, en poussant les anciennes données vers la gauche et en traçant les nouvelles données vers la droite, afin que je puisse visualiser en temps réel les informations fournies par le périphérique Bluetooth.
Je sais qu'il existe déjà un progiciel de graphisme, mais je ne suis pas très familier avec ce genre de choses et j'aimerais les appliquer en implémentant ce graphique moi-même.De plus, la plus grande partie de ma classe GraphView est terminée, sauf pour la partie courbe.
deuxième question, je me demande comment je devrais envoyer les nouvelles valeurs au graphique. Dois-je utiliser quelque chose comme une pile FIFO, ou puis-je réaliser ce que je veux avec une simple matrice de doubles? D'un côté, les 4 champs en bas sont déjà mis à jour dynamiquement. Eh bien, ils font semblant de simuler la "dynamique", ils bouclent à travers la même double matrice encore et encore, ils ne prennent pas réellement de nouvelles valeurs.
Merci pour votre temps! Si quelque chose n'est pas clair sur ma question, faites le moi savoir et je le mettrai à jour avec plus de détails.
pouvez-vous donner un lien pour tous les projets? ce look est très intéressant! –