##// END OF EJS Templates
Uses the same time spec (UTC) as axis for tooltips on graph
Alexandre Leroux -
r490:431d583ca834
parent child
Show More
@@ -1,161 +1,162
1 #include "Visualization/VisualizationGraphHelper.h"
1 #include "Visualization/VisualizationGraphHelper.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5
5
6 #include <Variable/Variable.h>
6 #include <Variable/Variable.h>
7
7
8 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
8 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
9
9
10 namespace {
10 namespace {
11
11
12 class SqpDataContainer : public QCPGraphDataContainer {
12 class SqpDataContainer : public QCPGraphDataContainer {
13 public:
13 public:
14 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
14 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
15 };
15 };
16
16
17
17
18 /// Format for datetimes on a axis
18 /// Format for datetimes on a axis
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
20
20
21 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
21 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
22 /// non-time data
22 /// non-time data
23 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
23 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
24 {
24 {
25 if (isTimeAxis) {
25 if (isTimeAxis) {
26 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
26 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
27 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
27 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
28 dateTicker->setDateTimeSpec(Qt::UTC);
28
29
29 return dateTicker;
30 return dateTicker;
30 }
31 }
31 else {
32 else {
32 // default ticker
33 // default ticker
33 return QSharedPointer<QCPAxisTicker>::create();
34 return QSharedPointer<QCPAxisTicker>::create();
34 }
35 }
35 }
36 }
36
37
37 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
38 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
38 const SqpDateTime &dateTime)
39 const SqpDateTime &dateTime)
39 {
40 {
40 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
41 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
41 << QThread::currentThread()->objectName();
42 << QThread::currentThread()->objectName();
42 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
43 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
43 scalarSeries.lockRead();
44 scalarSeries.lockRead();
44 {
45 {
45 const auto &xData = scalarSeries.xAxisData()->cdata();
46 const auto &xData = scalarSeries.xAxisData()->cdata();
46 const auto &valuesData = scalarSeries.valuesData()->cdata();
47 const auto &valuesData = scalarSeries.valuesData()->cdata();
47
48
48 auto xDataBegin = xData.cbegin();
49 auto xDataBegin = xData.cbegin();
49 auto xDataEnd = xData.cend();
50 auto xDataEnd = xData.cend();
50
51
51 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache"
52 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache"
52 << xData.count();
53 << xData.count();
53
54
54 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
55 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
55 qcpGraph->setData(sqpDataContainer);
56 qcpGraph->setData(sqpDataContainer);
56
57
57 auto lowerIt = std::lower_bound(xDataBegin, xDataEnd, dateTime.m_TStart);
58 auto lowerIt = std::lower_bound(xDataBegin, xDataEnd, dateTime.m_TStart);
58 auto upperIt = std::upper_bound(xDataBegin, xDataEnd, dateTime.m_TEnd);
59 auto upperIt = std::upper_bound(xDataBegin, xDataEnd, dateTime.m_TEnd);
59 auto distance = std::distance(xDataBegin, lowerIt);
60 auto distance = std::distance(xDataBegin, lowerIt);
60
61
61 auto valuesDataIt = valuesData.cbegin() + distance;
62 auto valuesDataIt = valuesData.cbegin() + distance;
62 for (auto xAxisDataIt = lowerIt; xAxisDataIt != upperIt;
63 for (auto xAxisDataIt = lowerIt; xAxisDataIt != upperIt;
63 ++xAxisDataIt, ++valuesDataIt) {
64 ++xAxisDataIt, ++valuesDataIt) {
64 sqpDataContainer->appendGraphData(QCPGraphData(*xAxisDataIt, *valuesDataIt));
65 sqpDataContainer->appendGraphData(QCPGraphData(*xAxisDataIt, *valuesDataIt));
65 }
66 }
66
67
67 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed"
68 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed"
68 << sqpDataContainer->size();
69 << sqpDataContainer->size();
69 }
70 }
70 scalarSeries.unlock();
71 scalarSeries.unlock();
71
72
72
73
73 // Display all data
74 // Display all data
74 component->parentPlot()->replot();
75 component->parentPlot()->replot();
75 }
76 }
76 else {
77 else {
77 /// @todo DEBUG
78 /// @todo DEBUG
78 }
79 }
79 }
80 }
80
81
81 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
82 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
82 const SqpDateTime &dateTime)
83 const SqpDateTime &dateTime)
83 {
84 {
84 auto component = plot.addGraph();
85 auto component = plot.addGraph();
85
86
86 if (component) {
87 if (component) {
87 // // Graph data
88 // // Graph data
88 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
89 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
89 true);
90 true);
90
91
91 updateScalarData(component, scalarSeries, dateTime);
92 updateScalarData(component, scalarSeries, dateTime);
92
93
93 // Axes properties
94 // Axes properties
94 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
95 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
95 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
96 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
96
97
97 auto setAxisProperties = [](auto axis, const auto &unit) {
98 auto setAxisProperties = [](auto axis, const auto &unit) {
98 // label (unit name)
99 // label (unit name)
99 axis->setLabel(unit.m_Name);
100 axis->setLabel(unit.m_Name);
100
101
101 // ticker (depending on the type of unit)
102 // ticker (depending on the type of unit)
102 axis->setTicker(axisTicker(unit.m_TimeUnit));
103 axis->setTicker(axisTicker(unit.m_TimeUnit));
103 };
104 };
104 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
105 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
105 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
106 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
106
107
107 // Display all data
108 // Display all data
108 component->rescaleAxes();
109 component->rescaleAxes();
109 plot.replot();
110 plot.replot();
110 }
111 }
111 else {
112 else {
112 qCDebug(LOG_VisualizationGraphHelper())
113 qCDebug(LOG_VisualizationGraphHelper())
113 << QObject::tr("Can't create graph for the scalar series");
114 << QObject::tr("Can't create graph for the scalar series");
114 }
115 }
115
116
116 return component;
117 return component;
117 }
118 }
118
119
119 } // namespace
120 } // namespace
120
121
121 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
122 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
122 QCustomPlot &plot) noexcept
123 QCustomPlot &plot) noexcept
123 {
124 {
124 auto result = QVector<QCPAbstractPlottable *>{};
125 auto result = QVector<QCPAbstractPlottable *>{};
125
126
126 if (variable) {
127 if (variable) {
127 // Gets the data series of the variable to call the creation of the right components
128 // Gets the data series of the variable to call the creation of the right components
128 // according to its type
129 // according to its type
129 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
130 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
130 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->dateTime()));
131 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->dateTime()));
131 }
132 }
132 else {
133 else {
133 qCDebug(LOG_VisualizationGraphHelper())
134 qCDebug(LOG_VisualizationGraphHelper())
134 << QObject::tr("Can't create graph plottables : unmanaged data series type");
135 << QObject::tr("Can't create graph plottables : unmanaged data series type");
135 }
136 }
136 }
137 }
137 else {
138 else {
138 qCDebug(LOG_VisualizationGraphHelper())
139 qCDebug(LOG_VisualizationGraphHelper())
139 << QObject::tr("Can't create graph plottables : the variable is null");
140 << QObject::tr("Can't create graph plottables : the variable is null");
140 }
141 }
141
142
142 return result;
143 return result;
143 }
144 }
144
145
145 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
146 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
146 IDataSeries *dataSeries, const SqpDateTime &dateTime)
147 IDataSeries *dataSeries, const SqpDateTime &dateTime)
147 {
148 {
148 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
149 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
149 if (plotableVect.size() == 1) {
150 if (plotableVect.size() == 1) {
150 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
151 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
151 }
152 }
152 else {
153 else {
153 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
154 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
154 "Can't update Data of a scalarSeries because there is not only one component "
155 "Can't update Data of a scalarSeries because there is not only one component "
155 "associated");
156 "associated");
156 }
157 }
157 }
158 }
158 else {
159 else {
159 /// @todo DEBUG
160 /// @todo DEBUG
160 }
161 }
161 }
162 }
@@ -1,118 +1,123
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Common/DateUtils.h>
5
4 namespace {
6 namespace {
5
7
6 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
8 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
7
9
8 const auto TEXT_TRACER_FORMAT = QStringLiteral("key: %1\nvalue: %2");
10 const auto TEXT_TRACER_FORMAT = QStringLiteral("key: %1\nvalue: %2");
9
11
10 /// Timeout after which a tracer is displayed
12 /// Timeout after which a tracer is displayed
11 const auto TRACER_TIMEOUT = 500;
13 const auto TRACER_TIMEOUT = 500;
12
14
13 /// Formats a data value according to the axis on which it is present
15 /// Formats a data value according to the axis on which it is present
14 QString formatValue(double value, const QCPAxis &axis)
16 QString formatValue(double value, const QCPAxis &axis)
15 {
17 {
16 // If the axis is a time axis, formats the value as a date
18 // If the axis is a time axis, formats the value as a date
17 return qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())
19 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
18 ? QCPAxisTickerDateTime::keyToDateTime(value).toString(DATETIME_FORMAT)
20 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
19 : QString::number(value);
21 }
22 else {
23 return QString::number(value);
24 }
20 }
25 }
21
26
22 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
27 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
23 {
28 {
24 tracer.setInterpolating(false);
29 tracer.setInterpolating(false);
25 tracer.setStyle(QCPItemTracer::tsPlus);
30 tracer.setStyle(QCPItemTracer::tsPlus);
26 tracer.setPen(QPen(Qt::black));
31 tracer.setPen(QPen(Qt::black));
27 tracer.setBrush(Qt::black);
32 tracer.setBrush(Qt::black);
28 tracer.setSize(10);
33 tracer.setSize(10);
29 }
34 }
30
35
31 void initTextTracerStyle(QCPItemText &tracer) noexcept
36 void initTextTracerStyle(QCPItemText &tracer) noexcept
32 {
37 {
33 tracer.setPen(QPen{Qt::gray});
38 tracer.setPen(QPen{Qt::gray});
34 tracer.setBrush(Qt::white);
39 tracer.setBrush(Qt::white);
35 tracer.setPadding(QMargins{6, 6, 6, 6});
40 tracer.setPadding(QMargins{6, 6, 6, 6});
36 tracer.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
41 tracer.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
37 tracer.setTextAlignment(Qt::AlignLeft);
42 tracer.setTextAlignment(Qt::AlignLeft);
38 }
43 }
39
44
40 } // namespace
45 } // namespace
41
46
42 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
47 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
43 explicit VisualizationGraphRenderingDelegatePrivate(QCustomPlot &plot)
48 explicit VisualizationGraphRenderingDelegatePrivate(QCustomPlot &plot)
44 : m_Plot{plot},
49 : m_Plot{plot},
45 m_PointTracer{new QCPItemTracer{&plot}},
50 m_PointTracer{new QCPItemTracer{&plot}},
46 m_TextTracer{new QCPItemText{&plot}},
51 m_TextTracer{new QCPItemText{&plot}},
47 m_TracerTimer{}
52 m_TracerTimer{}
48 {
53 {
49 initPointTracerStyle(*m_PointTracer);
54 initPointTracerStyle(*m_PointTracer);
50 initTextTracerStyle(*m_TextTracer);
55 initTextTracerStyle(*m_TextTracer);
51
56
52 m_TracerTimer.setInterval(TRACER_TIMEOUT);
57 m_TracerTimer.setInterval(TRACER_TIMEOUT);
53 m_TracerTimer.setSingleShot(true);
58 m_TracerTimer.setSingleShot(true);
54 }
59 }
55
60
56 QCustomPlot &m_Plot;
61 QCustomPlot &m_Plot;
57 QCPItemTracer *m_PointTracer;
62 QCPItemTracer *m_PointTracer;
58 QCPItemText *m_TextTracer;
63 QCPItemText *m_TextTracer;
59 QTimer m_TracerTimer;
64 QTimer m_TracerTimer;
60 };
65 };
61
66
62 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(QCustomPlot &plot)
67 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(QCustomPlot &plot)
63 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(plot)}
68 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(plot)}
64 {
69 {
65 }
70 }
66
71
67 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
72 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
68 {
73 {
69 // Cancels pending refresh
74 // Cancels pending refresh
70 impl->m_TracerTimer.disconnect();
75 impl->m_TracerTimer.disconnect();
71
76
72 auto showTracers = [ eventPos = event->pos(), this ]()
77 auto showTracers = [ eventPos = event->pos(), this ]()
73 {
78 {
74 // Lambda function to display a tracer
79 // Lambda function to display a tracer
75 auto displayTracer = [this](auto &tracer) {
80 auto displayTracer = [this](auto &tracer) {
76 // Tracer is set on top of the plot's main layer
81 // Tracer is set on top of the plot's main layer
77 tracer.setLayer(impl->m_Plot.layer("main"));
82 tracer.setLayer(impl->m_Plot.layer("main"));
78 tracer.setVisible(true);
83 tracer.setVisible(true);
79 impl->m_Plot.replot();
84 impl->m_Plot.replot();
80 };
85 };
81
86
82 // Reinits tracers
87 // Reinits tracers
83 impl->m_PointTracer->setGraph(nullptr);
88 impl->m_PointTracer->setGraph(nullptr);
84 impl->m_PointTracer->setVisible(false);
89 impl->m_PointTracer->setVisible(false);
85 impl->m_TextTracer->setVisible(false);
90 impl->m_TextTracer->setVisible(false);
86 impl->m_Plot.replot();
91 impl->m_Plot.replot();
87
92
88 // Gets the graph under the mouse position
93 // Gets the graph under the mouse position
89 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
94 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
90 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
95 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
91 auto graphData = graph->data();
96 auto graphData = graph->data();
92
97
93 // Gets the closest data point to the mouse
98 // Gets the closest data point to the mouse
94 auto graphDataIt = graphData->findBegin(mouseKey);
99 auto graphDataIt = graphData->findBegin(mouseKey);
95 if (graphDataIt != graphData->constEnd()) {
100 if (graphDataIt != graphData->constEnd()) {
96 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
101 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
97 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
102 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
98 impl->m_TextTracer->setText(TEXT_TRACER_FORMAT.arg(key, value));
103 impl->m_TextTracer->setText(TEXT_TRACER_FORMAT.arg(key, value));
99
104
100 // Displays point tracer
105 // Displays point tracer
101 impl->m_PointTracer->setGraph(graph);
106 impl->m_PointTracer->setGraph(graph);
102 impl->m_PointTracer->setGraphKey(mouseKey);
107 impl->m_PointTracer->setGraphKey(mouseKey);
103 displayTracer(*impl->m_PointTracer);
108 displayTracer(*impl->m_PointTracer);
104
109
105 // Displays text tracer
110 // Displays text tracer
106 auto tracerPosition = impl->m_TextTracer->position;
111 auto tracerPosition = impl->m_TextTracer->position;
107 tracerPosition->setAxes(graph->keyAxis(), graph->valueAxis());
112 tracerPosition->setAxes(graph->keyAxis(), graph->valueAxis());
108 tracerPosition->setCoords(impl->m_PointTracer->position->key(),
113 tracerPosition->setCoords(impl->m_PointTracer->position->key(),
109 impl->m_PointTracer->position->value());
114 impl->m_PointTracer->position->value());
110 displayTracer(*impl->m_TextTracer);
115 displayTracer(*impl->m_TextTracer);
111 }
116 }
112 }
117 }
113 };
118 };
114
119
115 // Starts the timer to display tracers at timeout
120 // Starts the timer to display tracers at timeout
116 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTracers);
121 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTracers);
117 impl->m_TracerTimer.start();
122 impl->m_TracerTimer.start();
118 }
123 }
General Comments 0
You need to be logged in to leave comments. Login now