Files
Jérôme Delacotte 7b30d6e298 first commit
2025-03-06 11:15:32 +01:00

169 lines
7.2 KiB
C++

#include "Graph.h"
Graph::Graph(Ecran * _ecran, Graph_Param _gp)
{
ecran = _ecran;
gp = _gp;
}
/*
INITIALCODE FROM (C) D L BIRD
This function will draw a graph on a ePaper/TFT/LCD display using data from an array containing data to be graphed.
The variable 'max_readings' determines the maximum number of data elements for each array. Call it with the following parametric data:
x_pos-the x axis top-left position of the graph
y_pos-the y-axis top-left position of the graph, e.g. 100, 200 would draw the graph 100 pixels along and 200 pixels down from the top-left of the screen
width-the width of the graph in pixels
height-height of the graph in pixels
Y1_Max-sets the scale of plotted data, for example 5000 would scale all data to a Y-axis of 5000 maximum
data_array1 is parsed by value, externally they can be called anything else, e.g. within the routine it is called data_array1, but externally could be temperature_readings
gp.auto_scale-a logical value (TRUE or FALSE) that switches the Y-axis autoscale On or Off
barchart_on-a logical value (TRUE or FALSE) that switches the drawing mode between barhcart and line graph
barchart_colour-a sets the gp.title and graph plotting colour
If called with Y!_Max value of 500 and the data never goes above 500, then autoscale will retain a 0-500 Y scale, if on, the scale increases/decreases to match the data.
gp.auto_scale_margin, e.g. if set to 1000 then autoscale increments the scale by 1000 steps.
Changed to be an object
add x gp.title
multiple gp.series
colors for gp.series
allow 2 scales
use Graph_Param
use enums
add thickness
add fill line mode
*/
// float DataArray[], int readings
void Graph::draw(int readings, int x_pos, int y_pos, int gwidth, int gheight) {
if (debug) Serial.println("B - graph::draw");
float maxYscale[2] = {-10000, -10000};
float minYscale[2] = {10000, 10000};
int last_x, last_y;
float x2, y2;
if (gp.auto_scale == DYNAMIC_SCALE) {
for (int s = 0; s < gp.nb_series; s++) {
int ref = 0;
if (gp.show_2_scales) {
ref = s;
}
for (int i = 1; i < readings; i++ ) {
if (gp.series[s].data[i] >= maxYscale[ref]) maxYscale[ref] = gp.series[s].data[i];
if (gp.series[s].data[i] <= minYscale[ref]) minYscale[ref] = gp.series[s].data[i];
}
}
for (int s = 0; s < gp.nb_series; s++) {
maxYscale[s] = round(maxYscale[s] + gp.auto_scale_margin); // Auto scale the graph and round to the nearest value defined, default was gp.Y_Max[ref]
gp.Y_Max[s] = round(maxYscale[s] + 0.5);
if (minYscale[s] != s) minYscale[s] = round(minYscale[s] - gp.auto_scale_margin); // Auto scale the graph and round to the nearest value defined, default was gp.Y_Min[ref]
gp.Y_Min[s] = round(minYscale[s]);
}
}
if (debug) Serial.println(" graph::draw "
+ String(gp.nb_series) + " " + String(x_pos) + " " + String(y_pos) + " "
+ String(gwidth) + " " + String(gheight) + " "
//+ String(last_x) + " " + String(last_y) + " "
+ String(gp.Y_Min[0]) + " " + String(gp.Y_Max[0]) + " "
+ String(gp.Y_Min[1]) + " " + String(gp.Y_Max[1])
);
ecran->_display->drawRect(x_pos, y_pos, gwidth + 3, gheight + 2, GxEPD_BLACK);
ecran->drawString(x_pos + gwidth / 2, y_pos - 13, gp.title, CENTER, GxEPD_BLACK);
// Draw the data
for (int s = 0; s < gp.nb_series; s++) {
int ref = 0;
if (gp.show_2_scales == TWO_SCALES) {
ref = s;
}
// Draw the graph
last_x = x_pos;
last_y = y_pos + (gp.Y_Max[ref] - constrain(gp.series[ref].data[1], gp.Y_Min[ref], gp.Y_Max[ref])) / (gp.Y_Max[ref] - gp.Y_Min[ref]) * gheight;
if (debug) Serial.print("Data to draw : S" + String(s) + " ");
for (int gx = 0; gx < readings; gx++) {
if (debug) Serial.print(gp.series[s].data[gx]);
if (debug) Serial.print(" ");
y2 = y_pos + (gp.Y_Max[ref] - constrain(gp.series[s].data[gx], gp.Y_Min[ref], gp.Y_Max[ref])) / (gp.Y_Max[ref] - gp.Y_Min[ref]) * gheight + 1;
if (gp.series[s].chart_type == TYPE_BARCHART) {
x2 = x_pos + gx * (gwidth / readings) + 2;
ecran->_display->fillRect(x2, y2,
(gwidth / readings) - 2,
y_pos + gheight - y2 + 2,
gp.series[s].color
);
}
else
{
x2 = x_pos + gx * gwidth / (readings - 1) + 1; // max_readings is the global variable that sets the maximum data that can be plotted
if (gp.series[s].chart_type == TYPE_FILL_LINE) {
if (last_y < y2) {
ecran->_display->fillTriangle(last_x, last_y, last_x, y2, x2, y2, gp.series[s].color);
}
else {
ecran->_display->fillTriangle(last_x, last_y, x2, last_y, x2, y2, gp.series[s].color);
}
float y0 = min((float) x2, (float) last_y);
ecran->_display->fillRect(x2, y0,
(gwidth / readings),
y_pos + gheight - y0 + 2,
gp.series[s].color);
ecran->_display->drawLine(last_x, last_y, x2, y2, GxEPD_BLACK);
}
else {
if (gp.series[s].thickness > 1) {
ecran->drawAngledLine(last_x, last_y, x2, y2, gp.series[s].thickness, gp.series[s].color);
}
else {
ecran->_display->drawLine(last_x, last_y, x2, y2, gp.series[s].color);
}
}
}
last_x = x2;
last_y = y2;
}
if (debug) Serial.println(" ");
}
if (debug) Serial.println(" ");
for (int spacing = 0; spacing <= gp.y_minor_axis; spacing++) {
for (int j = 0; j < gp.number_of_dashes; j++) { // Draw dashed graph grid lines
if (spacing < gp.y_minor_axis)
ecran->_display->drawFastHLine((x_pos + 3 + j * gwidth / gp.number_of_dashes), y_pos + (gheight * spacing / gp.y_minor_axis), gwidth / (2 * gp.number_of_dashes), GxEPD_BLACK);
}
for (int s = 0; s < (gp.show_2_scales ? 2 : 1); s++) {
int color = (gp.show_2_scales == TWO_SCALES ? gp.series[s].color : GxEPD_BLACK);
int xp = (s == 0 ? 0 : gwidth + 10);
if ((gp.Y_Max[s] - (float)(gp.Y_Max[s] - gp.Y_Min[s]) / gp.y_minor_axis * spacing) < 5) {
ecran->drawString(x_pos + xp - 1, y_pos + gheight * spacing / gp.y_minor_axis - 5,
String((gp.Y_Max[s] - (float)(gp.Y_Max[s] - gp.Y_Min[s]) / gp.y_minor_axis * spacing + 0.01), 1),
(s == 0 ? RIGHT : LEFT), color
);
}
else
{
if (gp.Y_Min[s] < 1 && gp.Y_Max[s] < 10)
ecran->drawString(x_pos + xp - 1, y_pos + gheight * spacing / gp.y_minor_axis - 5,
String((gp.Y_Max[s] - (float)(gp.Y_Max[s] - gp.Y_Min[s]) / gp.y_minor_axis * spacing + 0.01), 1),
(s == 0 ? RIGHT : LEFT), color);
else
ecran->drawString(x_pos + xp - 2, y_pos + gheight * spacing / gp.y_minor_axis - 5,
String((gp.Y_Max[s] - (float)(gp.Y_Max[s] - gp.Y_Min[s]) / gp.y_minor_axis * spacing + 0.01), 0),
(s == 0 ? RIGHT : LEFT), color);
}
}
}
// for (int i = 0; i <= 2; i++) {
// ecran->drawString(15 + x_pos + gwidth / 3 * i, y_pos + gheight + 3, String(i), LEFT);
// }
ecran->drawString(x_pos + gwidth / 2, y_pos + gheight + 14, gp.x_title, RIGHT);
if (debug) Serial.println("E - graph::draw");
}