Graphic DateTime axis improvements
This commit is contained in:
@@ -433,7 +433,7 @@ void Graphic::canvasPaintEvent() {
|
|||||||
gridborder += QPoint(font_sz.width(), font_sz.height());
|
gridborder += QPoint(font_sz.width(), font_sz.height());
|
||||||
if (hasLblY) gridborder += QPoint(font_sz.height(), 0);
|
if (hasLblY) gridborder += QPoint(font_sz.height(), 0);
|
||||||
if (hasLblX) gridborder += QPoint(0, font_sz.height());
|
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->setClipping(true);
|
||||||
painter->setClipRect(QRect(gridborder.x(), 0, wid - gridborder.x(), hei - gridborder.y()));
|
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);
|
painter->drawLine(cx, hei + 5, cx, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int cur_scl[7] = {0,0,0,0,0,0,0};
|
int dt_add[7] = {0,0,0,0,0,0,0};
|
||||||
const char * formats[2];
|
int dt_add_lo[7] = {0,0,0,0,0,0,0};
|
||||||
step = splitRangeDate(range, wid / gridx / font_sz.width() * 1.4, formats[0], formats[1], cur_scl);
|
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.) {
|
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;
|
//qDebug() << step << range << int(wid / gridx / font_sz.width() * 1.4) << cd;
|
||||||
roundDateTime(cd, cur_scl);
|
if (!is_years) {
|
||||||
cdp = cd;
|
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];
|
//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 {
|
struct Anchor {
|
||||||
int pix_x[2];
|
int pix_x[2];
|
||||||
QDateTime date;
|
QDateTime date;
|
||||||
};
|
};
|
||||||
QVector<Anchor> areas;
|
QVector<Anchor> areas_ce, areas_lo;
|
||||||
cnt = 1000;
|
cnt = 1000;
|
||||||
int area_start = gbx;
|
int area_start = gbx, area_start_lo = gbx;
|
||||||
|
pcx = real2canvasX(cd.toMSecsSinceEpoch() / grid_numbers_x);
|
||||||
while (cnt-- > 0) {
|
while (cnt-- > 0) {
|
||||||
addDateTime(cd, cur_scl);
|
addDateTime(cd, dt_add);
|
||||||
cdc = cd;
|
bool need_text = true;
|
||||||
roundDateTime(cdc, cur_scl);
|
if (!is_years) {
|
||||||
cx = real2canvasX(cd.toMSecsSinceEpoch() / grid_numbers_x);
|
cdc = cd;
|
||||||
if (cx < gbx) continue;
|
roundDateTime(cdc, dt_add);
|
||||||
if (cdp != cdc) {
|
cx = real2canvasX(cd.toMSecsSinceEpoch() / grid_numbers_x);
|
||||||
areas << Anchor{{area_start, qMin(cx, right)}, cdp};
|
if (cx < gbx) continue;
|
||||||
area_start = areas.back().pix_x[1];
|
if (cdp != cdc) {
|
||||||
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;
|
if (cx > right) break;
|
||||||
painter->setPen(grid_pen);
|
painter->setPen(grid_pen);
|
||||||
painter->drawLine(cx, hei + 5, cx, 0);
|
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);
|
painter->setPen(text_color);
|
||||||
int dx = -font_sz.height() / 4.;
|
|
||||||
painter->setFont(nf);
|
painter->setFont(nf);
|
||||||
str.first = cd.toString(formats[0]);
|
auto pfm = painter->fontMetrics();
|
||||||
painter->drawText(cx + dx, cy, str.first);
|
for (const auto & a: areas_ce) {
|
||||||
}
|
ds = a.date.toString(formats[1]);
|
||||||
if (area_start < right)
|
auto str_rect = pfm.boundingRect(ds);
|
||||||
areas << Anchor{{area_start, right}, cdc};
|
painter->drawText(a.pix_x[0] + (a.pix_x[1] - a.pix_x[0] - str_rect.width()) / 2, ce_y, ds);
|
||||||
painter->setPen(grid_pen);
|
}
|
||||||
for (const auto & a: areas) {
|
for (const auto & a: areas_lo) {
|
||||||
painter->drawLine(a.pix_x[0], hei + 5, a.pix_x[0], cy - font_sz.height());
|
ds = a.date.toString(formats[2]);
|
||||||
}
|
auto str_rect = pfm.boundingRect(ds);
|
||||||
painter->setPen(text_color);
|
painter->drawText(a.pix_x[0] + (a.pix_x[1] - a.pix_x[0] - str_rect.width()) / 2, lo_y, ds);
|
||||||
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]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
static const qint64
|
||||||
to_sec = 1000LL,
|
to_sec = 1000LL,
|
||||||
to_min = 1000LL * 60,
|
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;
|
to_year = 1000LL * 60 * 60 * 24 * 30 * 12;
|
||||||
static const struct {
|
static const struct {
|
||||||
const char * upper;
|
const char * upper;
|
||||||
|
const char * center;
|
||||||
const char * lower;
|
const char * lower;
|
||||||
} formats[] = {
|
} date_formats[] = {
|
||||||
{"ss.zzz 's'" , "yyyy MMM dd(ddd) h:mm:ss"},
|
{"ss.zzz 's'", "h 'h' mm 'm'", "yyyy MMM dd(ddd)"},
|
||||||
{"ss 's'" , "yyyy MMM dd(ddd) h:mm"},
|
{"ss 's'" , "h 'h' mm 'm'", "yyyy MMM dd(ddd)"},
|
||||||
{"mm 'm'" , "yyyy MMM dd(ddd) h 'h' "},
|
{"mm 'm'" , "h 'h'" , "yyyy MMM dd(ddd)"},
|
||||||
{"h 'h'" , "yyyy MMM dd(ddd)"},
|
{"h 'h'" , "dd(ddd)" , "yyyy MMM"},
|
||||||
{"dd(ddd)" , "yyyy MMM"},
|
{"dd(ddd)" , "MMM" , "yyyy"},
|
||||||
{"MMM" , "yyyy"},
|
{"MMM" , "yyyy" , ""},
|
||||||
{"yyyy" , ""}
|
{"yyyy" , "" , ""}
|
||||||
};
|
};
|
||||||
double ret = splitRange(range, count);
|
double ret = splitRange(range, count);
|
||||||
int format_index = 6;
|
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_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_hour ) {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_day ) {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_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 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);}
|
else {format_index = 6; step[6] = qRound64(ret / to_year);}
|
||||||
up_format = formats[format_index].upper;
|
formats[0] = date_formats[format_index].upper;
|
||||||
lo_format = formats[format_index].lower;
|
formats[1] = date_formats[format_index].center;
|
||||||
|
formats[2] = date_formats[format_index].lower;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -388,7 +388,7 @@ protected:
|
|||||||
void setRectToLines();
|
void setRectToLines();
|
||||||
void checkLines();
|
void checkLines();
|
||||||
double splitRange(double range, int count = 1);
|
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);
|
double roundTo(double value, double round_to);
|
||||||
void roundDateTime(QDateTime & dt, int c[7]);
|
void roundDateTime(QDateTime & dt, int c[7]);
|
||||||
void addDateTime(QDateTime & dt, int c[7], qint64 mul = 1);
|
void addDateTime(QDateTime & dt, int c[7], qint64 mul = 1);
|
||||||
|
|||||||
Reference in New Issue
Block a user