-
Notifications
You must be signed in to change notification settings - Fork 337
Scale network graph based on time interval #539
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9c9ea44
0fc40e3
55bae83
1d8a548
aaf1bc3
85b6adb
c7ac1b8
f0871d1
9094941
255774f
bb5b4cc
c0f46d2
874b2d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,9 +11,11 @@ | |
| #include <QColor> | ||
| #include <QTimer> | ||
|
|
||
| #include <chrono> | ||
| #include <cmath> | ||
| #include <cfloat> | ||
|
|
||
| #define DESIRED_SAMPLES 800 | ||
| #define DESIRED_SAMPLES 300 | ||
|
|
||
| #define XMARGIN 10 | ||
| #define YMARGIN 10 | ||
|
|
@@ -47,30 +49,43 @@ int TrafficGraphWidget::getGraphRangeMins() const | |
| return nMins; | ||
| } | ||
|
|
||
| int TrafficGraphWidget::y_value(float value) | ||
| { | ||
| int h = height() - YMARGIN * 2; | ||
| return YMARGIN + h - (h * 1.0 * (fToggle ? (pow(value, 0.30102) / pow(fMax, 0.30102)) : (value / fMax))); | ||
| } | ||
|
|
||
| void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples) | ||
| { | ||
| int sampleCount = samples.size(); | ||
| if(sampleCount > 0) { | ||
| if(sampleCount > 0 && fMax > 0) { | ||
| int h = height() - YMARGIN * 2, w = width() - XMARGIN * 2; | ||
| int x = XMARGIN + w; | ||
| path.moveTo(x, YMARGIN + h); | ||
| for(int i = 0; i < sampleCount; ++i) { | ||
| x = XMARGIN + w - w * i / DESIRED_SAMPLES; | ||
| int y = YMARGIN + h - (int)(h * samples.at(i) / fMax); | ||
| x = XMARGIN + w - w * i / DESIRED_SAMPLES / (getGraphRangeMins()/5); | ||
| int y = y_value(samples.at(i)); | ||
| path.lineTo(x, y); | ||
| } | ||
| path.lineTo(x, YMARGIN + h); | ||
| } | ||
| } | ||
|
|
||
| void TrafficGraphWidget::mouseDoubleClickEvent(QMouseEvent *event) | ||
| { | ||
| QWidget::mousePressEvent(event); | ||
| fToggle = !fToggle; | ||
| update(); | ||
| } | ||
|
|
||
| void TrafficGraphWidget::paintEvent(QPaintEvent *) | ||
| { | ||
| QPainter painter(this); | ||
| painter.fillRect(rect(), Qt::black); | ||
|
|
||
| if(fMax <= 0.0f) return; | ||
|
|
||
| QColor axisCol(Qt::gray); | ||
| QColor axisCol(QColor(78,78,78,255)); | ||
| int h = height() - YMARGIN * 2; | ||
| painter.setPen(axisCol); | ||
| painter.drawLine(XMARGIN, YMARGIN + h, width() - XMARGIN, YMARGIN + h); | ||
|
|
@@ -82,44 +97,55 @@ void TrafficGraphWidget::paintEvent(QPaintEvent *) | |
| const QString units = tr("kB/s"); | ||
| const float yMarginText = 2.0; | ||
|
|
||
| // draw lines | ||
| painter.setPen(axisCol); | ||
| painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units)); | ||
| for(float y = val; y < fMax; y += val) { | ||
| int yy = YMARGIN + h - h * y / fMax; | ||
| painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy); | ||
| } | ||
| // if we drew 3 or fewer lines, break them up at the next lower order of magnitude | ||
| if(fMax / val <= 3.0f) { | ||
| axisCol = axisCol.darker(); | ||
| // if we drew 10 or 3 fewer lines, break them up at the next lower order of magnitude | ||
| if(fMax / val <= (fToggle ? 10.0f : 3.0f)) { | ||
| float oldval = val; | ||
| val = pow(10.0f, base - 1); | ||
| painter.setPen(axisCol); | ||
| painter.drawText(XMARGIN, YMARGIN + h - h * val / fMax-yMarginText, QString("%1 %2").arg(val).arg(units)); | ||
| painter.setPen(axisCol.lighter()); | ||
| painter.drawText(XMARGIN, y_value(val)-yMarginText, QString("%1 %2").arg(val).arg(units)); | ||
| if (fToggle) { | ||
| int yy = y_value(val*0.1); | ||
| painter.drawText(XMARGIN, yy-yMarginText, QString("%1 %2").arg(val*0.1).arg(units)); | ||
| painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy); | ||
| } | ||
| int count = 1; | ||
| for(float y = val; y < fMax; y += val, count++) { | ||
| // don't overwrite lines drawn above | ||
| for(float y = val; y < (!fToggle || fMax / val < 20 ? fMax : oldval); y += val, count++) { | ||
| if(count % 10 == 0) | ||
| continue; | ||
| int yy = YMARGIN + h - h * y / fMax; | ||
| int yy = y_value(y); | ||
| painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy); | ||
| } | ||
| val = oldval; | ||
| } | ||
| // draw lines | ||
| painter.setPen(axisCol); | ||
| for(float y = val; y < fMax; y += val) { | ||
| int yy = y_value(y); | ||
| painter.drawLine(XMARGIN, yy, width() - XMARGIN, yy); | ||
| } | ||
| painter.drawText(XMARGIN, y_value(val)-yMarginText, QString("%1 %2").arg(val).arg(units)); | ||
|
|
||
| painter.setRenderHint(QPainter::Antialiasing); | ||
|
|
||
| if(!vSamplesIn.empty()) { | ||
| QPainterPath p; | ||
| paintPath(p, vSamplesIn); | ||
| painter.fillPath(p, QColor(0, 255, 0, 128)); | ||
| painter.setPen(Qt::green); | ||
| QPen ppen (QColor(0,255,0,0),0,Qt::SolidLine); | ||
| painter.setPen(ppen); | ||
| painter.fillPath(p, QColor(0, 255, 0, 255)); | ||
| painter.drawPath(p); | ||
| } | ||
|
|
||
| if(!vSamplesOut.empty()) { | ||
| QPainterPath p; | ||
| paintPath(p, vSamplesOut); | ||
| painter.fillPath(p, QColor(255, 0, 0, 128)); | ||
| painter.setPen(Qt::red); | ||
| QPen ppen (QColor(255,0,0,0),0,Qt::SolidLine); | ||
| painter.setPen(ppen); | ||
| painter.fillPath(p, QColor(255, 0, 0, 255)); | ||
| painter.drawPath(p); | ||
| } | ||
|
|
||
| painter.fillRect(0,0,XMARGIN,height(), Qt::black); | ||
| } | ||
|
|
||
| void TrafficGraphWidget::updateRates() | ||
|
|
@@ -135,32 +161,35 @@ void TrafficGraphWidget::updateRates() | |
| nLastBytesIn = bytesIn; | ||
| nLastBytesOut = bytesOut; | ||
|
|
||
| while(vSamplesIn.size() > DESIRED_SAMPLES) { | ||
| while(vSamplesIn.size() > FLT_MAX - 1) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how much memory does this need? concept ACK implementation NACK - it's unnecessary to store so many sample points, given the granulatory can be decreased as the times period gets longer. Resampling as the data gets older is a better way (as it avoids wasting memory on data that will never be displayed).
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree - I have been thinking about how to do this. Maybe pruning the list at larger intervals - keeping samples that are above a moving average. Open to suggestions on implementation. :) Thanks for looking at this!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can chunk the end of the list at DESIRED_SAMPLES intervals - calculate the moving average - pruning samples that fall below it. |
||
| vSamplesIn.pop_back(); | ||
| } | ||
| while(vSamplesOut.size() > DESIRED_SAMPLES) { | ||
| while(vSamplesOut.size() > FLT_MAX - 1) { | ||
| vSamplesOut.pop_back(); | ||
| } | ||
|
|
||
| float tmax = 0.0f; | ||
| for (const float f : vSamplesIn) { | ||
| for (const float f : vSamplesIn.mid(0,(DESIRED_SAMPLES*getGraphRangeMins()/5))) { | ||
| if(f > tmax) tmax = f; | ||
| } | ||
| for (const float f : vSamplesOut) { | ||
| for (const float f : vSamplesOut.mid(0,(DESIRED_SAMPLES*getGraphRangeMins()/5))) { | ||
| if(f > tmax) tmax = f; | ||
| } | ||
| fMax = tmax; | ||
| update(); | ||
| } | ||
|
|
||
| void TrafficGraphWidget::setGraphRangeMins(int mins) | ||
| void TrafficGraphWidget::setGraphRange(std::chrono::minutes new_range) | ||
| { | ||
| nMins = mins; | ||
| int msecsPerSample = nMins * 60 * 1000 / DESIRED_SAMPLES; | ||
| using namespace std::chrono_literals; | ||
| const auto range{new_range}; | ||
| nMins = new_range.count(); | ||
| auto msecs_per_sample = nMins * 60 * 1000 / (DESIRED_SAMPLES * (range.count() / 5)); | ||
| timer->stop(); | ||
| timer->setInterval(msecsPerSample); | ||
| timer->setInterval(msecs_per_sample); | ||
|
|
||
| clear(); | ||
| update(); | ||
| timer->start(); | ||
| } | ||
|
|
||
| void TrafficGraphWidget::clear() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't check to see if there was a Qt defined dark gray - It is ideal to let the samples stand out above the scale lines - we can tweak this. Note: there is plenty of room unused in the side panel - I have some code laying around to define user preferred color palettes - could be a useful feature for usability/accessibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A thought was to implement Solarized Light/Dark color palettes as user options - I am a fan - and plenty of research has gone into these color schemes.