##// END OF EJS Templates
Handles axes properties for spectrograms...
Alexandre Leroux -
r921:bea8fb891633
parent child
Show More
@@ -1,123 +1,163
1 1 #include "Visualization/AxisRenderingUtils.h"
2 2
3 3 #include <Data/ScalarSeries.h>
4 #include <Data/SpectrogramSeries.h>
4 5 #include <Data/VectorSeries.h>
5 6
6 7 #include <Visualization/qcustomplot.h>
7 8
8 9 namespace {
9 10
10 11 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
11 12
12 13 /// Format for datetimes on a axis
13 14 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
14 15
15 16 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
16 17 /// non-time data
17 18 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
18 19 {
19 20 if (isTimeAxis) {
20 21 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
21 22 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
22 23 dateTicker->setDateTimeSpec(Qt::UTC);
23 24
24 25 return dateTicker;
25 26 }
26 27 else {
27 28 // default ticker
28 29 return QSharedPointer<QCPAxisTicker>::create();
29 30 }
30 31 }
31 32
32 33 /**
33 34 * Sets properties of the axis passed as parameter
34 35 * @param axis the axis to set
35 36 * @param unit the unit to set for the axis
36 37 * @param scaleType the scale type to set for the axis
37 38 */
38 39 void setAxisProperties(QCPAxis &axis, const Unit &unit,
39 40 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
40 41 {
41 42 // label (unit name)
42 43 axis.setLabel(unit.m_Name);
43 44
44 45 // scale type
45 46 axis.setScaleType(scaleType);
46 47
47 48 // ticker (depending on the type of unit)
48 49 axis.setTicker(axisTicker(unit.m_TimeUnit));
49 50 }
50 51
51 52 /**
52 53 * Delegate used to set axes properties
53 54 */
54 55 template <typename T, typename Enabled = void>
55 56 struct AxisSetter {
56 57 static void setProperties(T &, QCustomPlot &, QCPColorScale &)
57 58 {
58 59 // Default implementation does nothing
59 60 }
60 61 };
61 62
62 63 /**
63 64 * Specialization of AxisSetter for scalars and vectors
64 65 * @sa ScalarSeries
65 66 * @sa VectorSeries
66 67 */
67 68 template <typename T>
68 69 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
69 70 or std::is_base_of<VectorSeries, T>::value> > {
70 71 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &)
71 72 {
72 73 dataSeries.lockRead();
73 74 auto xAxisUnit = dataSeries.xAxisUnit();
74 75 auto valuesUnit = dataSeries.valuesUnit();
75 76 dataSeries.unlock();
76 77
77 78 setAxisProperties(*plot.xAxis, xAxisUnit);
78 79 setAxisProperties(*plot.yAxis, valuesUnit);
79 80 }
80 81 };
81 82
82 83 /**
84 * Specialization of AxisSetter for spectrograms
85 * @sa SpectrogramSeries
86 */
87 template <typename T>
88 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
89 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &colorScale)
90 {
91 dataSeries.lockRead();
92 auto xAxisUnit = dataSeries.xAxisUnit();
93 /// @todo ALX: use iterators here
94 auto yAxisUnit = dataSeries.yAxis().unit();
95 auto valuesUnit = dataSeries.valuesUnit();
96 dataSeries.unlock();
97
98 setAxisProperties(*plot.xAxis, xAxisUnit);
99 setAxisProperties(*plot.yAxis, yAxisUnit);
100
101 // Displays color scale in plot
102 plot.plotLayout()->insertRow(0);
103 plot.plotLayout()->addElement(0, 0, &colorScale);
104 colorScale.setType(QCPAxis::atTop);
105 colorScale.setMinimumMargins(QMargins{0, 0, 0, 0});
106
107 // Aligns color scale with axes
108 auto marginGroups = plot.axisRect()->marginGroups();
109 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) {
110 colorScale.setMarginGroup(it.key(), it.value());
111 }
112
113 // Set color scale properties
114 colorScale.setLabel(valuesUnit.m_Name);
115 colorScale.setDataScaleType(QCPAxis::stLogarithmic); // Logarithmic scale
116 }
117 };
118
119 /**
83 120 * Default implementation of IAxisHelper, which takes data series to set axes properties
84 121 * @tparam T the data series' type
85 122 */
86 123 template <typename T>
87 124 struct AxisHelper : public IAxisHelper {
88 125 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
89 126
90 127 void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) override
91 128 {
92 129 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
93 130 }
94 131
95 132 T &m_DataSeries;
96 133 };
97 134
98 135 } // namespace
99 136
100 137 QString formatValue(double value, const QCPAxis &axis)
101 138 {
102 139 // If the axis is a time axis, formats the value as a date
103 140 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
104 141 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
105 142 }
106 143 else {
107 144 return QString::number(value);
108 145 }
109 146 }
110 147
111 148 std::unique_ptr<IAxisHelper>
112 149 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
113 150 {
114 151 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
115 152 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
116 153 }
154 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
155 return std::make_unique<AxisHelper<SpectrogramSeries> >(*spectrogramSeries);
156 }
117 157 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
118 158 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
119 159 }
120 160 else {
121 161 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
122 162 }
123 163 }
@@ -1,243 +1,245
1 1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 2 #include "Visualization/AxisRenderingUtils.h"
3 3 #include "Visualization/PlottablesRenderingUtils.h"
4 4 #include "Visualization/VisualizationGraphWidget.h"
5 5 #include "Visualization/qcustomplot.h"
6 6
7 7 #include <Common/DateUtils.h>
8 8
9 9 #include <Data/IDataSeries.h>
10 10
11 11 #include <SqpApplication.h>
12 12
13 13 namespace {
14 14
15 15 /// Name of the axes layer in QCustomPlot
16 16 const auto AXES_LAYER = QStringLiteral("axes");
17 17
18 18 /// Icon used to show x-axis properties
19 19 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
20 20
21 21 /// Name of the overlay layer in QCustomPlot
22 22 const auto OVERLAY_LAYER = QStringLiteral("overlay");
23 23
24 24 /// Pixmap used to show x-axis properties
25 25 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
26 26
27 27 const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
28 28
29 29 /// Offset used to shift the tooltip of the mouse
30 30 const auto TOOLTIP_OFFSET = QPoint{20, 20};
31 31
32 32 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
33 33 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
34 34
35 35 /// Timeout after which the tooltip is displayed
36 36 const auto TOOLTIP_TIMEOUT = 500;
37 37
38 38 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
39 39 {
40 40 tracer.setInterpolating(false);
41 41 tracer.setStyle(QCPItemTracer::tsCircle);
42 42 tracer.setSize(3);
43 43 tracer.setPen(QPen(Qt::black));
44 44 tracer.setBrush(Qt::black);
45 45 }
46 46
47 47 QPixmap pixmap(const QString &iconPath) noexcept
48 48 {
49 49 return QIcon{iconPath}.pixmap(QSize{16, 16});
50 50 }
51 51
52 52 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
53 53 {
54 54 // Icon
55 55 pixmap.setPixmap(
56 56 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
57 57
58 58 // Position
59 59 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
60 60 pixmap.topLeft->setCoords(1, 0);
61 61 pixmap.setClipToAxisRect(false);
62 62
63 63 // Can be selected
64 64 pixmap.setSelectable(true);
65 65 }
66 66
67 67 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
68 68 {
69 69 // Icon
70 70 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
71 71
72 72 // Position
73 73 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
74 74 itemPixmap.topLeft->setCoords(0, 1);
75 75 itemPixmap.setClipToAxisRect(false);
76 76
77 77 // Can be selected
78 78 itemPixmap.setSelectable(true);
79 79 }
80 80
81 81 void initTitleTextStyle(QCPItemText &text) noexcept
82 82 {
83 83 // Font and background styles
84 84 text.setColor(Qt::gray);
85 85 text.setBrush(Qt::white);
86 86
87 87 // Position
88 88 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
89 89 text.position->setType(QCPItemPosition::ptAxisRectRatio);
90 90 text.position->setCoords(0.5, 0);
91 91 }
92 92
93 93 } // namespace
94 94
95 95 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
96 96 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
97 97 : m_Plot{graphWidget.plot()},
98 98 m_PointTracer{new QCPItemTracer{&m_Plot}},
99 99 m_TracerTimer{},
100 100 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
101 101 m_TitleText{new QCPItemText{&m_Plot}},
102 102 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
103 103 m_ShowXAxis{true},
104 m_XAxisLabel{}
104 m_XAxisLabel{},
105 m_ColorScale{new QCPColorScale{&m_Plot}}
note

Who manage the delete of the color scale ?

105 106 {
106 107 initPointTracerStyle(*m_PointTracer);
107 108
108 109 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
109 110 m_TracerTimer.setSingleShot(true);
110 111
111 112 // Inits "close button" in plot overlay
112 113 m_ClosePixmap->setLayer(OVERLAY_LAYER);
113 114 initClosePixmapStyle(*m_ClosePixmap);
114 115
115 116 // Connects pixmap selection to graph widget closing
116 117 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
117 118 [&graphWidget](bool selected) {
118 119 if (selected) {
119 120 graphWidget.close();
120 121 }
121 122 });
122 123
123 124 // Inits graph name in plot overlay
124 125 m_TitleText->setLayer(OVERLAY_LAYER);
125 126 m_TitleText->setText(graphWidget.name());
126 127 initTitleTextStyle(*m_TitleText);
127 128
128 129 // Inits "show x-axis button" in plot overlay
129 130 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
130 131 initXAxisPixmapStyle(*m_XAxisPixmap);
131 132
132 133 // Connects pixmap selection to graph x-axis showing/hiding
133 134 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
134 135 if (m_XAxisPixmap->selected()) {
135 136 // Changes the selection state and refreshes the x-axis
136 137 m_ShowXAxis = !m_ShowXAxis;
137 138 updateXAxisState();
138 139 m_Plot.layer(AXES_LAYER)->replot();
139 140
140 141 // Deselects the x-axis pixmap and updates icon
141 142 m_XAxisPixmap->setSelected(false);
142 143 m_XAxisPixmap->setPixmap(
143 144 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
144 145 m_Plot.layer(OVERLAY_LAYER)->replot();
145 146 }
146 147 });
147 148 }
148 149
149 150 /// Updates state of x-axis according to the current selection of x-axis pixmap
150 151 /// @remarks the method doesn't call plot refresh
151 152 void updateXAxisState() noexcept
152 153 {
153 154 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
154 155 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
155 156 }
156 157
157 158 QCustomPlot &m_Plot;
158 159 QCPItemTracer *m_PointTracer;
159 160 QTimer m_TracerTimer;
160 161 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
161 162 QCPItemText *m_TitleText; /// Graph's title
162 163 QCPItemPixmap *m_XAxisPixmap;
163 164 bool m_ShowXAxis; /// X-axis properties are shown or hidden
164 165 QString m_XAxisLabel;
166 QCPColorScale *m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
165 167 };
166 168
167 169 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
168 170 VisualizationGraphWidget &graphWidget)
169 171 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
170 172 {
171 173 }
172 174
173 175 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
174 176 {
175 177 // Cancels pending refresh
176 178 impl->m_TracerTimer.disconnect();
177 179
178 180 // Reinits tracers
179 181 impl->m_PointTracer->setGraph(nullptr);
180 182 impl->m_PointTracer->setVisible(false);
181 183 impl->m_Plot.replot();
182 184
183 185 // Gets the graph under the mouse position
184 186 auto eventPos = event->pos();
185 187 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
186 188 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
187 189 auto graphData = graph->data();
188 190
189 191 // Gets the closest data point to the mouse
190 192 auto graphDataIt = graphData->findBegin(mouseKey);
191 193 if (graphDataIt != graphData->constEnd()) {
192 194 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
193 195 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
194 196
195 197 // Displays point tracer
196 198 impl->m_PointTracer->setGraph(graph);
197 199 impl->m_PointTracer->setGraphKey(graphDataIt->key);
198 200 impl->m_PointTracer->setLayer(
199 201 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
200 202 impl->m_PointTracer->setVisible(true);
201 203 impl->m_Plot.replot();
202 204
203 205 // Starts timer to show tooltip after timeout
204 206 auto showTooltip = [ tooltip = TOOLTIP_FORMAT.arg(key, value), eventPos, this ]()
205 207 {
206 208 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
207 209 &impl->m_Plot, TOOLTIP_RECT);
208 210 };
209 211
210 212 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
211 213 impl->m_TracerTimer.start();
212 214 }
213 215 }
214 216 }
215 217
216 218 void VisualizationGraphRenderingDelegate::setAxesProperties(
217 219 std::shared_ptr<IDataSeries> dataSeries) noexcept
218 220 {
219 221 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
220 222 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
221 223
222 224 auto axisHelper = IAxisHelperFactory::create(dataSeries);
223 225 axisHelper->setProperties(impl->m_Plot, *impl->m_ColorScale);
224 226
225 227 // Updates x-axis state
226 228 impl->updateXAxisState();
227 229
228 230 impl->m_Plot.layer(AXES_LAYER)->replot();
229 231 }
230 232
231 233 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
232 234 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
233 235 {
234 236 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
235 237 plottablesHelper->setProperties(plottables);
236 238 }
237 239
238 240 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
239 241 {
240 242 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
241 243 overlay->setVisible(show);
242 244 overlay->replot();
243 245 }
General Comments 0
You need to be logged in to leave comments. Login now