10using namespace display;
12static const char *
const TAG =
"graph";
13static const char *
const TAGL =
"graphlegend";
32 ESP_LOGV(TAG,
"Updating trace with value: %f", data);
34 if (!std::isnan(data)) {
38 for (
int i = 0; i < this->
length_; i++) {
39 if (!std::isnan(this->
samples_[i])) {
50 ESP_LOGI(TAG,
"Init trace for sensor %s", this->
get_name().c_str());
68 float mx = trace->get_tracedata()->get_recent_max();
69 float mn = trace->get_tracedata()->get_recent_min();
70 if (std::isnan(ymax) || (ymax < mx))
72 if (std::isnan(ymin) || (ymin > mn))
81 float yrange = ymax - ymin;
86 for (uint32_t i = 0; i < this->
width_; i++) {
88 float v = trace->get_tracedata()->get_value(i);
94 if (std::isnan(mx) || (v > mx))
96 if (std::isnan(mn) || (v < mn))
102 if (!std::isnan(mn)) {
106 ESP_LOGV(TAG,
"Graphing at max_range. Using local min %f, max %f", mn, mx);
114 if (yrange > 10 * y_per_div) {
115 while (yrange > 10 * y_per_div) {
118 ESP_LOGW(TAG,
"Graphing reducing y-scale to prevent too many gridlines");
124 if (!std::isnan(ymin) && !std::isnan(ymax)) {
125 yn = (int) floorf(ymin / y_per_div);
126 ym = (int) ceilf(ymax / y_per_div);
130 ymin = yn * y_per_div;
131 ymax = ym * y_per_div;
132 yrange = ymax - ymin;
141 for (
int y = yn;
y <= ym;
y++) {
142 int16_t py = (int16_t) roundf((this->
height_ - 1) * (1.0 - (
float) (
y - yn) / (ym - yn)));
143 for (uint32_t
x = 0;
x < this->
width_;
x += 2) {
155 ESP_LOGW(TAG,
"Graphing reducing x-scale to prevent too many gridlines");
157 for (
int i = 0; i <= n; i++) {
158 for (uint32_t
y = 0;
y < this->
height_;
y += 2) {
165 ESP_LOGV(TAG,
"Updating graph. ymin %f, ymax %f", ymin, ymax);
167 Color c = trace->get_line_color();
168 int16_t thick = trace->get_line_thickness();
169 bool continuous = trace->get_continuous();
170 bool has_prev =
false;
173 for (uint32_t i = 0; i < this->
width_; i++) {
174 float v = (trace->get_tracedata()->get_value(i) - ymin) / yrange;
175 if (!std::isnan(v) && (thick > 0)) {
176 int16_t
x = this->width_ - 1 - i + x_offset;
178 bool b = (trace->get_line_type() & bit) == bit;
180 int16_t
y = (int16_t) roundf((this->
height_ - 1) * (1.0 - v)) - thick / 2 + y_offset;
181 auto draw_pixel_at = [&buff, c, y_offset,
this](int16_t
x, int16_t
y) {
182 if (
y >= y_offset &&
static_cast<uint32_t
>(
y) < y_offset + this->
height_)
185 if (!continuous || !has_prev || !prev_b || (abs(
y - prev_y) <= thick)) {
186 for (int16_t t = 0; t < thick; t++) {
187 draw_pixel_at(
x,
y + t);
190 int16_t mid_y = (
y + prev_y + thick) / 2;
192 for (int16_t t = prev_y + thick; t <= mid_y; t++)
193 draw_pixel_at(
x + 1, t);
194 for (int16_t t = mid_y + 1; t <
y + thick; t++)
197 for (int16_t t = prev_y - 1; t >= mid_y; t--)
198 draw_pixel_at(
x + 1, t);
199 for (int16_t t = mid_y - 1; t >=
y; t--)
219 int txtw = 0, txth = 0;
220 int valw = 0, valh = 0;
222 for (
auto *trace : g->
traces_) {
223 std::string txtstr = trace->get_name();
224 int fw, fos, fbl, fh;
230 if (trace->get_line_thickness() > lt)
231 lt = trace->get_line_thickness();
232 ESP_LOGI(TAGL,
" %s %d %d", txtstr.c_str(), fw, fh);
235 char valstr[VALUE_ACCURACY_MAX_LEN];
238 trace->sensor_->get_unit_of_measurement_ref());
247 ESP_LOGI(TAGL,
" %s %d %d", valstr, fw, fh);
255 uint16_t w = this->
width_;
263 this->
yl_ = txth + (txth / 4) + lt / 2;
278 this->
yv_ = txth + (txth / 4);
280 this->
yv_ += txth / 4 + lt;
282 this->
xv_ = (txtw + valw) / 2;
287 this->
x0_ = txtw / 2;
290 this->
xs_ = std::max(txtw, valw);
292 this->
x0_ = this->
xs_ / 2;
294 this->
xs_ = txtw + valw;
303 this->
x0_ = this->
xs_ / 2;
309 this->
ys_ = txth + txth / 2 + valh;
315 this->
ys_ = std::max(txth + txth / 4 + lt + txth / 4, valh + valh / 4);
317 this->
ys_ = std::max(txth + txth / 4, valh + valh / 4);
354 std::string txtstr = trace->get_name();
355 ESP_LOGV(TAG,
" %s", txtstr.c_str());
360 uint16_t thick = trace->get_line_thickness();
361 for (
int i = 0; i <
legend_->
x0_ * 4 / 3; i++) {
363 if (((uint8_t) trace->get_line_type() & (1 << b)) == (1 << b)) {
365 trace->get_line_color());
373 char valstr[VALUE_ACCURACY_MAX_LEN];
376 trace->sensor_->get_unit_of_measurement_ref());
381 ESP_LOGV(TAG,
" value: %s", valstr);
396 ESP_LOGCONFIG(TAG,
"Graph for sensor %s", trace->get_name().c_str());
virtual void measure(const char *str, int *width, int *x_offset, int *baseline, int *height)=0
void horizontal_line(int x, int y, int width, Color color=COLOR_ON)
Draw a horizontal line from the point [x,y] to [x+width,y] with the given color.
void printf(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,...) __attribute__((format(printf
Evaluate the printf-format format and print the result with the anchor point at [x,...
void draw_pixel_at(int x, int y)
Set a single pixel at the specified coordinates to default color.
void vertical_line(int x, int y, int height, Color color=COLOR_ON)
Draw a vertical line from the point [x,y] to [x,y+width] with the given color.
void dump_config() override
float graph_limit_min_
in pixels
void draw(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color)
std::vector< GraphTrace * > traces_
uint32_t width_
in seconds
void draw_legend(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color)
uint32_t height_
in pixels
display::BaseFont * font_label_
display::BaseFont * font_value_
void init(Graph *g)
Determine the best coordinates of drawing text + lines.
ValuePositionType values_
void set_update_time_ms(uint32_t update_time_ms)
void take_sample(float data)
std::vector< float > samples_
uint32_t update_time_
in ms
void add_on_state_callback(std::function< void(float)> &&callback)
Add a callback that will be called every time a filtered value arrives.
@ VALUE_POSITION_TYPE_NONE
@ VALUE_POSITION_TYPE_AUTO
@ VALUE_POSITION_TYPE_BELOW
@ VALUE_POSITION_TYPE_BESIDE
@ DIRECTION_TYPE_HORIZONTAL
@ DIRECTION_TYPE_VERTICAL
Providing packet encoding functions for exchanging data with a remote host.
size_t value_accuracy_to_buf(std::span< char, VALUE_ACCURACY_MAX_LEN > buf, float value, int8_t accuracy_decimals)
Format value with accuracy to buffer, returns chars written (excluding null)
size_t value_accuracy_with_uom_to_buf(std::span< char, VALUE_ACCURACY_MAX_LEN > buf, float value, int8_t accuracy_decimals, StringRef unit_of_measurement)
Format value with accuracy and UOM to buffer, returns chars written (excluding null)
uint32_t IRAM_ATTR HOT millis()