##// END OF EJS Templates
Merge branch 'feature/GraphTooltip' into develop
Alexandre Leroux -
r448:7eb12825208d merge
parent child
Show More
@@ -0,0 +1,20
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
2 #define SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
3
4 #include <Common/spimpl.h>
5
6 class QCustomPlot;
7 class QMouseEvent;
8
9 class VisualizationGraphRenderingDelegate {
10 public:
11 explicit VisualizationGraphRenderingDelegate(QCustomPlot &plot);
12
13 void onMouseMove(QMouseEvent *event) noexcept;
14
15 private:
16 class VisualizationGraphRenderingDelegatePrivate;
17 spimpl::unique_impl_ptr<VisualizationGraphRenderingDelegatePrivate> impl;
18 };
19
20 #endif // SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
@@ -0,0 +1,118
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 #include "Visualization/qcustomplot.h"
3
4 namespace {
5
6 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
7
8 const auto TEXT_TRACER_FORMAT = QStringLiteral("key: %1\nvalue: %2");
9
10 /// Timeout after which a tracer is displayed
11 const auto TRACER_TIMEOUT = 500;
12
13 /// Formats a data value according to the axis on which it is present
14 QString formatValue(double value, const QCPAxis &axis)
15 {
16 // If the axis is a time axis, formats the value as a date
17 return qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())
18 ? QCPAxisTickerDateTime::keyToDateTime(value).toString(DATETIME_FORMAT)
19 : QString::number(value);
20 }
21
22 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
23 {
24 tracer.setInterpolating(false);
25 tracer.setStyle(QCPItemTracer::tsPlus);
26 tracer.setPen(QPen(Qt::black));
27 tracer.setBrush(Qt::black);
28 tracer.setSize(10);
29 }
30
31 void initTextTracerStyle(QCPItemText &tracer) noexcept
32 {
33 tracer.setPen(QPen{Qt::gray});
34 tracer.setBrush(Qt::white);
35 tracer.setPadding(QMargins{6, 6, 6, 6});
36 tracer.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
37 tracer.setTextAlignment(Qt::AlignLeft);
38 }
39
40 } // namespace
41
42 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
43 explicit VisualizationGraphRenderingDelegatePrivate(QCustomPlot &plot)
44 : m_Plot{plot},
45 m_PointTracer{new QCPItemTracer{&plot}},
46 m_TextTracer{new QCPItemText{&plot}},
47 m_TracerTimer{}
48 {
49 initPointTracerStyle(*m_PointTracer);
50 initTextTracerStyle(*m_TextTracer);
51
52 m_TracerTimer.setInterval(TRACER_TIMEOUT);
53 m_TracerTimer.setSingleShot(true);
54 }
55
56 QCustomPlot &m_Plot;
57 QCPItemTracer *m_PointTracer;
58 QCPItemText *m_TextTracer;
59 QTimer m_TracerTimer;
60 };
61
62 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(QCustomPlot &plot)
63 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(plot)}
64 {
65 }
66
67 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
68 {
69 // Cancels pending refresh
70 impl->m_TracerTimer.disconnect();
71
72 auto showTracers = [ eventPos = event->pos(), this ]()
73 {
74 // Lambda function to display a tracer
75 auto displayTracer = [this](auto &tracer) {
76 // Tracer is set on top of the plot's main layer
77 tracer.setLayer(impl->m_Plot.layer("main"));
78 tracer.setVisible(true);
79 impl->m_Plot.replot();
80 };
81
82 // Reinits tracers
83 impl->m_PointTracer->setGraph(nullptr);
84 impl->m_PointTracer->setVisible(false);
85 impl->m_TextTracer->setVisible(false);
86 impl->m_Plot.replot();
87
88 // Gets the graph under the mouse position
89 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
90 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
91 auto graphData = graph->data();
92
93 // Gets the closest data point to the mouse
94 auto graphDataIt = graphData->findBegin(mouseKey);
95 if (graphDataIt != graphData->constEnd()) {
96 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
97 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
98 impl->m_TextTracer->setText(TEXT_TRACER_FORMAT.arg(key, value));
99
100 // Displays point tracer
101 impl->m_PointTracer->setGraph(graph);
102 impl->m_PointTracer->setGraphKey(mouseKey);
103 displayTracer(*impl->m_PointTracer);
104
105 // Displays text tracer
106 auto tracerPosition = impl->m_TextTracer->position;
107 tracerPosition->setAxes(graph->keyAxis(), graph->valueAxis());
108 tracerPosition->setCoords(impl->m_PointTracer->position->key(),
109 impl->m_PointTracer->position->value());
110 displayTracer(*impl->m_TextTracer);
111 }
112 }
113 };
114
115 // Starts the timer to display tracers at timeout
116 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTracers);
117 impl->m_TracerTimer.start();
118 }
@@ -69,6 +69,8 private slots:
69 /// Rescale the X axe to range parameter
69 /// Rescale the X axe to range parameter
70 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
70 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
71
71
72 /// Slot called when a mouse move was made
73 void onMouseMove(QMouseEvent *event) noexcept;
72 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
74 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
73 void onMouseWheel(QWheelEvent *event) noexcept;
75 void onMouseWheel(QWheelEvent *event) noexcept;
74 /// Slot called when a mouse press was made, to activate the calibration of a graph
76 /// Slot called when a mouse press was made, to activate the calibration of a graph
@@ -1,6 +1,7
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationGraphHelper.h"
3 #include "Visualization/VisualizationGraphHelper.h"
4 #include "Visualization/VisualizationGraphRenderingDelegate.h"
4 #include "ui_VisualizationGraphWidget.h"
5 #include "ui_VisualizationGraphWidget.h"
5
6
6 #include <Data/ArrayData.h>
7 #include <Data/ArrayData.h>
@@ -33,17 +34,21 double toleranceValue(const QString &key, double defaultValue) noexcept
33
34
34 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
35 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
35
36
36 explicit VisualizationGraphWidgetPrivate() : m_DoSynchronize{true}, m_IsCalibration{false} {}
37 explicit VisualizationGraphWidgetPrivate()
37
38 : m_DoSynchronize{true}, m_IsCalibration{false}, m_RenderingDelegate{nullptr}
39 {
40 }
38
41
39 // Return the operation when range changed
42 // Return the operation when range changed
40 VisualizationGraphWidgetZoomType getZoomType(const QCPRange &t1, const QCPRange &t2);
43 VisualizationGraphWidgetZoomType getZoomType(const QCPRange &t1, const QCPRange &t2);
41
44
42 // 1 variable -> n qcpplot
45 // 1 variable -> n qcpplot
43 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
46 std::multimap<std::shared_ptr<Variable>, QCPAbstractPlottable *> m_VariableToPlotMultiMap;
44
45 bool m_DoSynchronize;
47 bool m_DoSynchronize;
46 bool m_IsCalibration;
48 bool m_IsCalibration;
49 QCPItemTracer *m_TextTracer;
50 /// Delegate used to attach rendering features to the plot
51 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
47 };
52 };
48
53
49 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
54 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
@@ -53,6 +58,9 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget
53 {
58 {
54 ui->setupUi(this);
59 ui->setupUi(this);
55
60
61 // The delegate must be initialized after the ui as it uses the plot
62 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*ui->widget);
63
56 ui->graphNameLabel->setText(name);
64 ui->graphNameLabel->setText(name);
57
65
58 // 'Close' options : widget is deleted when closed
66 // 'Close' options : widget is deleted when closed
@@ -65,9 +73,11 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget
65 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
73 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
66 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
74 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
67 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
75 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
76
68 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
77 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
69 connect(ui->widget, &QCustomPlot::mouseRelease, this,
78 connect(ui->widget, &QCustomPlot::mouseRelease, this,
70 &VisualizationGraphWidget::onMouseRelease);
79 &VisualizationGraphWidget::onMouseRelease);
80 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
71 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
81 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
72 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
82 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
73 &QCPAxis::rangeChanged),
83 &QCPAxis::rangeChanged),
@@ -329,6 +339,12 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange
329 }
339 }
330 }
340 }
331
341
342 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
343 {
344 // Handles plot rendering when mouse is moving
345 impl->m_RenderingDelegate->onMouseMove(event);
346 }
347
332 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
348 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
333 {
349 {
334 auto zoomOrientations = QFlags<Qt::Orientation>{};
350 auto zoomOrientations = QFlags<Qt::Orientation>{};
General Comments 0
You need to be logged in to leave comments. Login now