169 lines
7.2 KiB
C++
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");
|
|
|
|
} |