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