From 2e22a393dcf0c43eca3fd8938aaea13447f15ab1 Mon Sep 17 00:00:00 2001 From: peri4 Date: Thu, 24 Nov 2022 12:46:53 +0300 Subject: [PATCH] Graphic DateTime axis improvements --- libs/graphic/graphic.cpp | 152 ++++++++++++++++++++++++++------------- libs/graphic/graphic.h | 2 +- 2 files changed, 104 insertions(+), 50 deletions(-) diff --git a/libs/graphic/graphic.cpp b/libs/graphic/graphic.cpp index 4d19911..52075e4 100644 --- a/libs/graphic/graphic.cpp +++ b/libs/graphic/graphic.cpp @@ -433,7 +433,7 @@ void Graphic::canvasPaintEvent() { gridborder += QPoint(font_sz.width(), font_sz.height()); if (hasLblY) gridborder += QPoint(font_sz.height(), 0); if (hasLblX) gridborder += QPoint(0, font_sz.height()); - if (axis_type_x == DateTime) gridborder += QPoint(0, font_sz.height()); + if (axis_type_x == DateTime) gridborder += QPoint(0, font_sz.height() * 2); } painter->setClipping(true); painter->setClipRect(QRect(gridborder.x(), 0, wid - gridborder.x(), hei - gridborder.y())); @@ -1285,53 +1285,105 @@ void Graphic::drawGrid() { painter->drawLine(cx, hei + 5, cx, 0); } } else { - int cur_scl[7] = {0,0,0,0,0,0,0}; - const char * formats[2]; - step = splitRangeDate(range, wid / gridx / font_sz.width() * 1.4, formats[0], formats[1], cur_scl); + int dt_add[7] = {0,0,0,0,0,0,0}; + int dt_add_lo[7] = {0,0,0,0,0,0,0}; + const char * formats[3]; + step = splitRangeDate(range, wid / gridx / font_sz.width() / 1.5, formats, dt_add); + for (int i = 0; i < 6; ++i) dt_add_lo[i + 1] = dt_add[i]; + bool is_years = QString(formats[1]).isEmpty(); if (step > 0.) { - QDateTime cd = QDateTime::fromMSecsSinceEpoch(canvas2realX(gbx) * grid_numbers_x), cdp, cdc; + int up_y = cy - font_sz.height() * 2; + int ce_y = cy - font_sz.height(); + int lo_y = cy; + int ddx = 0, pcx = 0; + QDateTime cd = QDateTime::fromMSecsSinceEpoch(canvas2realX(gbx) * grid_numbers_x), cdp, cdc, cdl, cdlp; + QString ds; //qDebug() << step << range << int(wid / gridx / font_sz.width() * 1.4) << cd; - roundDateTime(cd, cur_scl); - cdp = cd; + if (!is_years) { + roundDateTime(cd, dt_add); + cdp = cdl = cdlp = cd; + roundDateTime(cdl, dt_add_lo); + roundDateTime(cdlp, dt_add_lo); + } else { + cd.setTime(QTime(0, 0, 0)); + cd.setDate(QDate(roundTo(cd.date().year(), dt_add[6]) - dt_add[6], 1, 1)); + } //qDebug() << cd << cur_scl[0] << cur_scl[1] << cur_scl[2] << cur_scl[3] << cur_scl[4] << cur_scl[5] << cur_scl[6]; struct Anchor { int pix_x[2]; QDateTime date; }; - QVector areas; + QVector areas_ce, areas_lo; cnt = 1000; - int area_start = gbx; + int area_start = gbx, area_start_lo = gbx; + pcx = real2canvasX(cd.toMSecsSinceEpoch() / grid_numbers_x); while (cnt-- > 0) { - addDateTime(cd, cur_scl); - cdc = cd; - roundDateTime(cdc, cur_scl); - cx = real2canvasX(cd.toMSecsSinceEpoch() / grid_numbers_x); - if (cx < gbx) continue; - if (cdp != cdc) { - areas << Anchor{{area_start, qMin(cx, right)}, cdp}; - area_start = areas.back().pix_x[1]; - cdp = cdc; + addDateTime(cd, dt_add); + bool need_text = true; + if (!is_years) { + cdc = cd; + roundDateTime(cdc, dt_add); + cx = real2canvasX(cd.toMSecsSinceEpoch() / grid_numbers_x); + if (cx < gbx) continue; + if (cdp != cdc) { + int cxc = real2canvasX(cdc.toMSecsSinceEpoch() / grid_numbers_x); + //qDebug() << cx << cxc << ddx << pcx; + if ((qAbs(cxc - cx) < ddx) && (cx != cxc)) need_text = false; + areas_ce << Anchor{{area_start, qMin(cxc, right)}, cdp}; + area_start = areas_ce.back().pix_x[1]; + cd = cdl = cdp = cdc; + cx = cxc; + roundDateTime(cdl, dt_add_lo); + if (cdlp != cdl) { + areas_lo << Anchor{{area_start_lo, qMin(cxc, right)}, cdlp}; + cdlp = cdl; + area_start_lo = areas_lo.back().pix_x[1]; + } + } else { + ddx = (cx - pcx) * 0.95; + } + pcx = cx; + } else { + cx = real2canvasX(cd.toMSecsSinceEpoch() / grid_numbers_x); + if (cx < gbx) continue; } if (cx > right) break; painter->setPen(grid_pen); painter->drawLine(cx, hei + 5, cx, 0); + if (need_text) { + painter->setPen(text_color); + int dx = -font_sz.height() / 4.; + painter->setFont(nf); + painter->drawText(cx + dx, up_y, cd.toString(formats[0])); + } + } + if (!is_years) { + if (area_start < right) + areas_ce << Anchor{{area_start, right}, cdc}; + if (area_start_lo < right) + areas_lo << Anchor{{area_start_lo, right}, cdl}; + //qDebug() << areas_lo.size() << formats[2] << areas_lo[0].date; + painter->setPen(grid_pen); + for (const auto & a: areas_ce) { + painter->drawLine(a.pix_x[0], hei + 5, a.pix_x[0], ce_y); + } + for (const auto & a: areas_lo) { + painter->drawLine(a.pix_x[0], ce_y, a.pix_x[0], lo_y); + } + painter->setPen(text_color); - int dx = -font_sz.height() / 4.; painter->setFont(nf); - str.first = cd.toString(formats[0]); - painter->drawText(cx + dx, cy, str.first); - } - if (area_start < right) - areas << Anchor{{area_start, right}, cdc}; - painter->setPen(grid_pen); - for (const auto & a: areas) { - painter->drawLine(a.pix_x[0], hei + 5, a.pix_x[0], cy - font_sz.height()); - } - painter->setPen(text_color); - painter->setFont(nf); - for (const auto & a: areas) { - QRect r(a.pix_x[0], cy - (2 * font_sz.height()), a.pix_x[1] - a.pix_x[0], font_sz.height()); - painter->drawText(r, Qt::AlignCenter | Qt::TextDontClip, a.date.toString(formats[1])); + auto pfm = painter->fontMetrics(); + for (const auto & a: areas_ce) { + ds = a.date.toString(formats[1]); + auto str_rect = pfm.boundingRect(ds); + painter->drawText(a.pix_x[0] + (a.pix_x[1] - a.pix_x[0] - str_rect.width()) / 2, ce_y, ds); + } + for (const auto & a: areas_lo) { + ds = a.date.toString(formats[2]); + auto str_rect = pfm.boundingRect(ds); + painter->drawText(a.pix_x[0] + (a.pix_x[1] - a.pix_x[0] - str_rect.width()) / 2, lo_y, ds); + } } } } @@ -1646,7 +1698,7 @@ double Graphic::splitRange(double range, int count) { } -double Graphic::splitRangeDate(double range, int count, const char *& up_format, const char *& lo_format, int step[7]) { +double Graphic::splitRangeDate(double range, int count, const char ** formats, int step[7]) { static const qint64 to_sec = 1000LL, to_min = 1000LL * 60, @@ -1656,27 +1708,29 @@ double Graphic::splitRangeDate(double range, int count, const char *& up_format, to_year = 1000LL * 60 * 60 * 24 * 30 * 12; static const struct { const char * upper; + const char * center; const char * lower; - } formats[] = { - {"ss.zzz 's'" , "yyyy MMM dd(ddd) h:mm:ss"}, - {"ss 's'" , "yyyy MMM dd(ddd) h:mm"}, - {"mm 'm'" , "yyyy MMM dd(ddd) h 'h' "}, - {"h 'h'" , "yyyy MMM dd(ddd)"}, - {"dd(ddd)" , "yyyy MMM"}, - {"MMM" , "yyyy"}, - {"yyyy" , ""} + } date_formats[] = { + {"ss.zzz 's'", "h 'h' mm 'm'", "yyyy MMM dd(ddd)"}, + {"ss 's'" , "h 'h' mm 'm'", "yyyy MMM dd(ddd)"}, + {"mm 'm'" , "h 'h'" , "yyyy MMM dd(ddd)"}, + {"h 'h'" , "dd(ddd)" , "yyyy MMM"}, + {"dd(ddd)" , "MMM" , "yyyy"}, + {"MMM" , "yyyy" , ""}, + {"yyyy" , "" , ""} }; double ret = splitRange(range, count); int format_index = 6; - if (ret < to_sec / 3 ) {format_index = 0; step[0] = qRound64(ret);} + if (ret < to_sec / 2 ) {format_index = 0; step[0] = qRound64(ret);} else if (ret < to_min / 2 ) {format_index = 1; step[1] = roundToNearest(ret / to_sec , {1, 2, 5, 10, 15, 20, 30});} - else if (ret < to_hour / 2 ) {format_index = 2; step[2] = roundToNearest(ret / to_min , {1, 2, 5, 10, 15, 20, 30});} - else if (ret < to_day / 2 ) {format_index = 3; step[3] = roundToNearest(ret / to_hour , {1, 2, 3, 4, 6, 8, 12});} - else if (ret < to_month / 1.5) {format_index = 4; step[4] = roundToNearest(ret / to_day , {1, 2, 5, 10});} + else if (ret < to_hour ) {format_index = 2; step[2] = roundToNearest(ret / to_min , {1, 2, 5, 10, 15, 20, 30});} + else if (ret < to_day ) {format_index = 3; step[3] = roundToNearest(ret / to_hour , {1, 2, 3, 4, 6, 8, 12});} + else if (ret < to_month / 1.6) {format_index = 4; step[4] = roundToNearest(ret / to_day , {1, 2, 5, 10});} else if (ret < to_year ) {format_index = 5; step[5] = roundToNearest(ret / to_month, {1, 2, 3, 4, 6});} - else {format_index = 6; step[6] = qRound64(ret);} - up_format = formats[format_index].upper; - lo_format = formats[format_index].lower; + else {format_index = 6; step[6] = qRound64(ret / to_year);} + formats[0] = date_formats[format_index].upper; + formats[1] = date_formats[format_index].center; + formats[2] = date_formats[format_index].lower; return ret; } diff --git a/libs/graphic/graphic.h b/libs/graphic/graphic.h index 1e703c0..f29e7a7 100644 --- a/libs/graphic/graphic.h +++ b/libs/graphic/graphic.h @@ -388,7 +388,7 @@ protected: void setRectToLines(); void checkLines(); double splitRange(double range, int count = 1); - double splitRangeDate(double range, int count, const char *& up_format, const char *& lo_format, int step[7]); + double splitRangeDate(double range, int count, const char ** formats, int step[7]); double roundTo(double value, double round_to); void roundDateTime(QDateTime & dt, int c[7]); void addDateTime(QDateTime & dt, int c[7], qint64 mul = 1);