##// END OF EJS Templates
Fix setting the axis title...
Titta Heikkala -
r2608:001bc2f70487
parent child
Show More
@@ -1,197 +1,198
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "cartesianchartaxis_p.h"
22 22 #include "qabstractaxis.h"
23 23 #include "qabstractaxis_p.h"
24 24 #include "chartpresenter_p.h"
25 25 #include "abstractchartlayout_p.h"
26 26 #include "abstractdomain_p.h"
27 27 #include "linearrowitem_p.h"
28 28 #include <QValueAxis>
29 29 #include <QLogValueAxis>
30 30 #include <QGraphicsLayout>
31 31 #include <QTextDocument>
32 32
33 33 QTCOMMERCIALCHART_BEGIN_NAMESPACE
34 34
35 35 CartesianChartAxis::CartesianChartAxis(QAbstractAxis *axis, QGraphicsItem *item , bool intervalAxis)
36 36 : ChartAxisElement(axis, item, intervalAxis)
37 37 {
38 38 Q_ASSERT(item);
39 39 }
40 40
41 41
42 42 CartesianChartAxis::~CartesianChartAxis()
43 43 {
44 44 }
45 45
46 46 void CartesianChartAxis::createItems(int count)
47 47 {
48 48 if (arrowItems().size() == 0) {
49 49 QGraphicsLineItem *arrow = new LineArrowItem(this, this);
50 50 arrow->setPen(axis()->linePen());
51 51 arrowGroup()->addToGroup(arrow);
52 52 }
53 53
54 54 if (intervalAxis() && gridItems().size() == 0) {
55 55 for (int i = 0 ; i < 2 ; i ++){
56 56 QGraphicsLineItem *item = new QGraphicsLineItem(this);
57 57 item->setPen(axis()->gridLinePen());
58 58 gridGroup()->addToGroup(item);
59 59 }
60 60 }
61 61
62 QGraphicsTextItem *title = titleItem();
63 title->setFont(axis()->titleFont());
64 title->setDefaultTextColor(axis()->titleBrush().color());
65 title->setHtml(axis()->titleText());
66
62 67 for (int i = 0; i < count; ++i) {
63 68 QGraphicsLineItem *arrow = new QGraphicsLineItem(this);
64 69 QGraphicsLineItem *grid = new QGraphicsLineItem(this);
65 70 QGraphicsTextItem *label = new QGraphicsTextItem(this);
66 71 label->document()->setDocumentMargin(ChartPresenter::textMargin());
67 QGraphicsTextItem *title = titleItem();
68 72 arrow->setPen(axis()->linePen());
69 73 grid->setPen(axis()->gridLinePen());
70 74 label->setFont(axis()->labelsFont());
71 75 label->setDefaultTextColor(axis()->labelsBrush().color());
72 76 label->setRotation(axis()->labelsAngle());
73 title->setFont(axis()->titleFont());
74 title->setDefaultTextColor(axis()->titleBrush().color());
75 title->setHtml(axis()->titleText());
76 77 arrowGroup()->addToGroup(arrow);
77 78 gridGroup()->addToGroup(grid);
78 79 labelGroup()->addToGroup(label);
79 80
80 81 if ((gridItems().size()) % 2 && gridItems().size() > 2) {
81 82 QGraphicsRectItem* shades = new QGraphicsRectItem(this);
82 83 shades->setPen(axis()->shadesPen());
83 84 shades->setBrush(axis()->shadesBrush());
84 85 shadeGroup()->addToGroup(shades);
85 86 }
86 87 }
87 88
88 89 }
89 90
90 91 void CartesianChartAxis::deleteItems(int count)
91 92 {
92 93 QList<QGraphicsItem *> lines = gridItems();
93 94 QList<QGraphicsItem *> labels = labelItems();
94 95 QList<QGraphicsItem *> shades = shadeItems();
95 96 QList<QGraphicsItem *> axis = arrowItems();
96 97
97 98 for (int i = 0; i < count; ++i) {
98 99 if (lines.size() % 2 && lines.size() > 1)
99 100 delete(shades.takeLast());
100 101 delete(lines.takeLast());
101 102 delete(labels.takeLast());
102 103 delete(axis.takeLast());
103 104 }
104 105 }
105 106
106 107 void CartesianChartAxis::updateLayout(QVector<qreal> &layout)
107 108 {
108 109 int diff = ChartAxisElement::layout().size() - layout.size();
109 110
110 111 if (diff > 0)
111 112 deleteItems(diff);
112 113 else if (diff < 0)
113 114 createItems(-diff);
114 115
115 116 if (animation()) {
116 117 switch (presenter()->state()) {
117 118 case ChartPresenter::ZoomInState:
118 119 animation()->setAnimationType(AxisAnimation::ZoomInAnimation);
119 120 animation()->setAnimationPoint(presenter()->statePoint());
120 121 break;
121 122 case ChartPresenter::ZoomOutState:
122 123 animation()->setAnimationType(AxisAnimation::ZoomOutAnimation);
123 124 animation()->setAnimationPoint(presenter()->statePoint());
124 125 break;
125 126 case ChartPresenter::ScrollUpState:
126 127 case ChartPresenter::ScrollLeftState:
127 128 animation()->setAnimationType(AxisAnimation::MoveBackwordAnimation);
128 129 break;
129 130 case ChartPresenter::ScrollDownState:
130 131 case ChartPresenter::ScrollRightState:
131 132 animation()->setAnimationType(AxisAnimation::MoveForwardAnimation);
132 133 break;
133 134 case ChartPresenter::ShowState:
134 135 animation()->setAnimationType(AxisAnimation::DefaultAnimation);
135 136 break;
136 137 }
137 138 animation()->setValues(ChartAxisElement::layout(), layout);
138 139 presenter()->startAnimation(animation());
139 140 } else {
140 141 setLayout(layout);
141 142 updateGeometry();
142 143 }
143 144 }
144 145
145 146 bool CartesianChartAxis::isEmpty()
146 147 {
147 148 return axisGeometry().isEmpty()
148 149 || gridGeometry().isEmpty()
149 150 || qFuzzyCompare(min(), max());
150 151 }
151 152
152 153 void CartesianChartAxis::setGeometry(const QRectF &axis, const QRectF &grid)
153 154 {
154 155 m_gridRect = grid;
155 156 setAxisGeometry(axis);
156 157
157 158 if (isEmpty())
158 159 return;
159 160
160 161 QVector<qreal> layout = calculateLayout();
161 162 updateLayout(layout);
162 163 }
163 164
164 165 QSizeF CartesianChartAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
165 166 {
166 167 Q_UNUSED(which);
167 168 Q_UNUSED(constraint);
168 169 return QSizeF();
169 170 }
170 171
171 172 void CartesianChartAxis::handleArrowPenChanged(const QPen &pen)
172 173 {
173 174 foreach (QGraphicsItem *item, arrowItems())
174 175 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
175 176 }
176 177
177 178 void CartesianChartAxis::handleGridPenChanged(const QPen &pen)
178 179 {
179 180 foreach (QGraphicsItem *item, gridItems())
180 181 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
181 182 }
182 183
183 184 void CartesianChartAxis::handleShadesBrushChanged(const QBrush &brush)
184 185 {
185 186 foreach (QGraphicsItem *item, shadeItems())
186 187 static_cast<QGraphicsRectItem *>(item)->setBrush(brush);
187 188 }
188 189
189 190 void CartesianChartAxis::handleShadesPenChanged(const QPen &pen)
190 191 {
191 192 foreach (QGraphicsItem *item, shadeItems())
192 193 static_cast<QGraphicsRectItem *>(item)->setPen(pen);
193 194 }
194 195
195 196 #include "moc_cartesianchartaxis_p.cpp"
196 197
197 198 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,354 +1,355
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "chartaxiselement_p.h"
22 22 #include "qabstractaxis_p.h"
23 23 #include "chartpresenter_p.h"
24 24 #include "abstractchartlayout_p.h"
25 25 #include <qmath.h>
26 26 #include <QDateTime>
27 27 #include <QTextDocument>
28 28
29 29 QTCOMMERCIALCHART_BEGIN_NAMESPACE
30 30
31 31 static const char *labelFormatMatchString = "%[\\-\\+#\\s\\d\\.lhjztL]*([dicuoxfegXFEG])";
32 32 static QRegExp *labelFormatMatcher = 0;
33 33 class StaticLabelFormatMatcherDeleter
34 34 {
35 35 public:
36 36 StaticLabelFormatMatcherDeleter() {}
37 37 ~StaticLabelFormatMatcherDeleter() { delete labelFormatMatcher; }
38 38 };
39 39 static StaticLabelFormatMatcherDeleter staticLabelFormatMatcherDeleter;
40 40
41 41 ChartAxisElement::ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
42 42 : ChartElement(item),
43 43 m_axis(axis),
44 44 m_animation(0),
45 45 m_grid(new QGraphicsItemGroup(item)),
46 46 m_arrow(new QGraphicsItemGroup(item)),
47 47 m_shades(new QGraphicsItemGroup(item)),
48 48 m_labels(new QGraphicsItemGroup(item)),
49 49 m_title(new QGraphicsTextItem(item)),
50 50 m_intervalAxis(intervalAxis)
51 51
52 52 {
53 53 //initial initialization
54 54 m_arrow->setHandlesChildEvents(false);
55 55 m_arrow->setZValue(ChartPresenter::AxisZValue);
56 56 m_labels->setZValue(ChartPresenter::AxisZValue);
57 57 m_shades->setZValue(ChartPresenter::ShadesZValue);
58 58 m_grid->setZValue(ChartPresenter::GridZValue);
59 59 m_title->setZValue(ChartPresenter::GridZValue);
60 60 m_title->document()->setDocumentMargin(ChartPresenter::textMargin());
61 61 handleVisibleChanged(axis->isVisible());
62 62 connectSlots();
63 63
64 64 setFlag(QGraphicsItem::ItemHasNoContents, true);
65 65 }
66 66
67 67 ChartAxisElement::~ChartAxisElement()
68 68 {
69 69 }
70 70
71 71 void ChartAxisElement::connectSlots()
72 72 {
73 73 QObject::connect(axis(), SIGNAL(visibleChanged(bool)), this, SLOT(handleVisibleChanged(bool)));
74 74 QObject::connect(axis(), SIGNAL(lineVisibleChanged(bool)), this, SLOT(handleArrowVisibleChanged(bool)));
75 75 QObject::connect(axis(), SIGNAL(gridVisibleChanged(bool)), this, SLOT(handleGridVisibleChanged(bool)));
76 76 QObject::connect(axis(), SIGNAL(labelsVisibleChanged(bool)), this, SLOT(handleLabelsVisibleChanged(bool)));
77 77 QObject::connect(axis(), SIGNAL(shadesVisibleChanged(bool)), this, SLOT(handleShadesVisibleChanged(bool)));
78 78 QObject::connect(axis(), SIGNAL(labelsAngleChanged(int)), this, SLOT(handleLabelsAngleChanged(int)));
79 79 QObject::connect(axis(), SIGNAL(linePenChanged(const QPen&)), this, SLOT(handleArrowPenChanged(const QPen&)));
80 80 QObject::connect(axis(), SIGNAL(labelsPenChanged(const QPen&)), this, SLOT(handleLabelsPenChanged(const QPen&)));
81 81 QObject::connect(axis(), SIGNAL(labelsBrushChanged(const QBrush&)), this, SLOT(handleLabelsBrushChanged(const QBrush&)));
82 82 QObject::connect(axis(), SIGNAL(labelsFontChanged(const QFont&)), this, SLOT(handleLabelsFontChanged(const QFont&)));
83 83 QObject::connect(axis(), SIGNAL(gridLinePenChanged(const QPen&)), this, SLOT(handleGridPenChanged(const QPen&)));
84 84 QObject::connect(axis(), SIGNAL(shadesPenChanged(const QPen&)), this, SLOT(handleShadesPenChanged(const QPen&)));
85 85 QObject::connect(axis(), SIGNAL(shadesBrushChanged(const QBrush&)), this, SLOT(handleShadesBrushChanged(const QBrush&)));
86 86 QObject::connect(axis(), SIGNAL(titleTextChanged(const QString&)), this, SLOT(handleTitleTextChanged(const QString&)));
87 87 QObject::connect(axis(), SIGNAL(titleFontChanged(const QFont&)), this, SLOT(handleTitleFontChanged(const QFont&)));
88 88 QObject::connect(axis(), SIGNAL(titlePenChanged(const QPen&)), this, SLOT(handleTitlePenChanged(const QPen&)));
89 89 QObject::connect(axis(), SIGNAL(titleBrushChanged(const QBrush&)), this, SLOT(handleTitleBrushChanged(const QBrush&)));
90 90 QObject::connect(axis(), SIGNAL(titleVisibleChanged(bool)), this, SLOT(handleTitleVisibleChanged(bool)));
91 91 QObject::connect(axis()->d_ptr.data(), SIGNAL(rangeChanged(qreal, qreal)), this, SLOT(handleRangeChanged(qreal, qreal)));
92 92 }
93 93
94 94 void ChartAxisElement::handleArrowVisibleChanged(bool visible)
95 95 {
96 96 m_arrow->setVisible(visible);
97 97 }
98 98
99 99 void ChartAxisElement::handleGridVisibleChanged(bool visible)
100 100 {
101 101 m_grid->setVisible(visible);
102 102 }
103 103
104 104 void ChartAxisElement::handleLabelsVisibleChanged(bool visible)
105 105 {
106 106 QGraphicsLayoutItem::updateGeometry();
107 107 presenter()->layout()->invalidate();
108 108 m_labels->setVisible(visible);
109 109 }
110 110
111 111 void ChartAxisElement::handleShadesVisibleChanged(bool visible)
112 112 {
113 113 m_shades->setVisible(visible);
114 114 }
115 115
116 116 void ChartAxisElement::handleTitleVisibleChanged(bool visible)
117 117 {
118 118 QGraphicsLayoutItem::updateGeometry();
119 119 presenter()->layout()->invalidate();
120 120 m_title->setVisible(visible);
121 121 }
122 122
123 123 void ChartAxisElement::handleLabelsAngleChanged(int angle)
124 124 {
125 125 foreach (QGraphicsItem *item, m_labels->childItems())
126 126 item->setRotation(angle);
127 127
128 128 QGraphicsLayoutItem::updateGeometry();
129 129 presenter()->layout()->invalidate();
130 130 }
131 131
132 132 void ChartAxisElement::handleLabelsPenChanged(const QPen &pen)
133 133 {
134 134 Q_UNUSED(pen)
135 135 }
136 136
137 137 void ChartAxisElement::handleLabelsBrushChanged(const QBrush &brush)
138 138 {
139 139 foreach (QGraphicsItem *item, m_labels->childItems())
140 140 static_cast<QGraphicsTextItem *>(item)->setDefaultTextColor(brush.color());
141 141 }
142 142
143 143 void ChartAxisElement::handleLabelsFontChanged(const QFont &font)
144 144 {
145 145 foreach (QGraphicsItem *item, m_labels->childItems())
146 146 static_cast<QGraphicsTextItem *>(item)->setFont(font);
147 147 QGraphicsLayoutItem::updateGeometry();
148 148 presenter()->layout()->invalidate();
149 149 }
150 150
151 151 void ChartAxisElement::handleTitleTextChanged(const QString &title)
152 152 {
153 153 QGraphicsLayoutItem::updateGeometry();
154 154 presenter()->layout()->invalidate();
155 m_title->setHtml(title);
155 if (title.isEmpty() || !m_title->isVisible())
156 m_title->setHtml(title);
156 157 }
157 158
158 159 void ChartAxisElement::handleTitlePenChanged(const QPen &pen)
159 160 {
160 161 Q_UNUSED(pen)
161 162 }
162 163
163 164 void ChartAxisElement::handleTitleBrushChanged(const QBrush &brush)
164 165 {
165 166 m_title->setDefaultTextColor(brush.color());
166 167 }
167 168
168 169 void ChartAxisElement::handleTitleFontChanged(const QFont &font)
169 170 {
170 171 if (m_title->font() != font) {
171 172 m_title->setFont(font);
172 173 QGraphicsLayoutItem::updateGeometry();
173 174 presenter()->layout()->invalidate();
174 175 }
175 176 }
176 177
177 178 void ChartAxisElement::handleVisibleChanged(bool visible)
178 179 {
179 180 setVisible(visible);
180 181 if (!visible) {
181 182 m_grid->setVisible(visible);
182 183 m_arrow->setVisible(visible);
183 184 m_shades->setVisible(visible);
184 185 m_labels->setVisible(visible);
185 186 m_title->setVisible(visible);
186 187 } else {
187 188 m_grid->setVisible(axis()->isGridLineVisible());
188 189 m_arrow->setVisible(axis()->isLineVisible());
189 190 m_shades->setVisible(axis()->shadesVisible());
190 191 m_labels->setVisible(axis()->labelsVisible());
191 192 m_title->setVisible(axis()->isTitleVisible());
192 193 }
193 194
194 195 if (presenter()) presenter()->layout()->invalidate();
195 196 }
196 197
197 198 void ChartAxisElement::handleRangeChanged(qreal min, qreal max)
198 199 {
199 200 Q_UNUSED(min);
200 201 Q_UNUSED(max);
201 202
202 203 if (!isEmpty()) {
203 204 QVector<qreal> layout = calculateLayout();
204 205 updateLayout(layout);
205 206 QSizeF before = effectiveSizeHint(Qt::PreferredSize);
206 207 QSizeF after = sizeHint(Qt::PreferredSize);
207 208
208 209 if (before != after) {
209 210 QGraphicsLayoutItem::updateGeometry();
210 211 // We don't want to call invalidate on layout, since it will change minimum size of
211 212 // component, which we would like to avoid since it causes nasty flips when scrolling
212 213 // or zooming, instead recalculate layout and use plotArea for extra space.
213 214 presenter()->layout()->setGeometry(presenter()->layout()->geometry());
214 215 }
215 216 }
216 217 }
217 218
218 219 bool ChartAxisElement::isEmpty()
219 220 {
220 221 return axisGeometry().isEmpty()
221 222 || gridGeometry().isEmpty()
222 223 || qFuzzyCompare(min(), max());
223 224 }
224 225
225 226 qreal ChartAxisElement::min() const
226 227 {
227 228 return m_axis->d_ptr->min();
228 229 }
229 230
230 231 qreal ChartAxisElement::max() const
231 232 {
232 233 return m_axis->d_ptr->max();
233 234 }
234 235
235 236 static void appendFormattedLabel(const QString &capStr, const QByteArray &array,
236 237 QStringList &labels, qreal value)
237 238 {
238 239 if (capStr.isEmpty()) {
239 240 labels << QString();
240 241 } else if (capStr.at(0) == QLatin1Char('d')
241 242 || capStr.at(0) == QLatin1Char('i')
242 243 || capStr.at(0) == QLatin1Char('c')) {
243 244 labels << QString().sprintf(array, (qint64)value);
244 245 } else if (capStr.at(0) == QLatin1Char('u')
245 246 || capStr.at(0) == QLatin1Char('o')
246 247 || capStr.at(0) == QLatin1Char('x')
247 248 || capStr.at(0) == QLatin1Char('X')) {
248 249 labels << QString().sprintf(array, (quint64)value);
249 250 } else if (capStr.at(0) == QLatin1Char('f')
250 251 || capStr.at(0) == QLatin1Char('F')
251 252 || capStr.at(0) == QLatin1Char('e')
252 253 || capStr.at(0) == QLatin1Char('E')
253 254 || capStr.at(0) == QLatin1Char('g')
254 255 || capStr.at(0) == QLatin1Char('G')) {
255 256 labels << QString().sprintf(array, value);
256 257 } else {
257 258 labels << QString();
258 259 }
259 260 }
260 261
261 262 QStringList ChartAxisElement::createValueLabels(qreal min, qreal max, int ticks, const QString &format)
262 263 {
263 264 QStringList labels;
264 265
265 266 if (max <= min || ticks < 1)
266 267 return labels;
267 268
268 269 int n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0);
269 270 n++;
270 271
271 272 if (format.isNull()) {
272 273 for (int i = 0; i < ticks; i++) {
273 274 qreal value = min + (i * (max - min) / (ticks - 1));
274 275 labels << QString::number(value, 'f', n);
275 276 }
276 277 } else {
277 278 QByteArray array = format.toLatin1();
278 279 QString capStr;
279 280 if (!labelFormatMatcher)
280 281 labelFormatMatcher = new QRegExp(labelFormatMatchString);
281 282 if (labelFormatMatcher->indexIn(format, 0) != -1)
282 283 capStr = labelFormatMatcher->cap(1);
283 284 for (int i = 0; i < ticks; i++) {
284 285 qreal value = min + (i * (max - min) / (ticks - 1));
285 286 appendFormattedLabel(capStr, array, labels, value);
286 287 }
287 288 }
288 289
289 290 return labels;
290 291 }
291 292
292 293 QStringList ChartAxisElement::createLogValueLabels(qreal min, qreal max, qreal base, int ticks, const QString &format)
293 294 {
294 295 QStringList labels;
295 296
296 297 if (max <= min || ticks < 1)
297 298 return labels;
298 299
299 300 int n = 0;
300 301 if (ticks > 1)
301 302 n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0);
302 303 n++;
303 304
304 305 int firstTick;
305 306 if (base > 1)
306 307 firstTick = ceil(log10(min) / log10(base));
307 308 else
308 309 firstTick = ceil(log10(max) / log10(base));
309 310
310 311 if (format.isNull()) {
311 312 for (int i = firstTick; i < ticks + firstTick; i++) {
312 313 qreal value = qPow(base, i);
313 314 labels << QString::number(value, 'f', n);
314 315 }
315 316 } else {
316 317 QByteArray array = format.toLatin1();
317 318 QString capStr;
318 319 if (!labelFormatMatcher)
319 320 labelFormatMatcher = new QRegExp(labelFormatMatchString);
320 321 if (labelFormatMatcher->indexIn(format, 0) != -1)
321 322 capStr = labelFormatMatcher->cap(1);
322 323 for (int i = firstTick; i < ticks + firstTick; i++) {
323 324 qreal value = qPow(base, i);
324 325 appendFormattedLabel(capStr, array, labels, value);
325 326 }
326 327 }
327 328
328 329 return labels;
329 330 }
330 331
331 332 QStringList ChartAxisElement::createDateTimeLabels(qreal min, qreal max,int ticks,const QString &format)
332 333 {
333 334 QStringList labels;
334 335
335 336 if (max <= min || ticks < 1)
336 337 return labels;
337 338
338 339 int n = qMax(int(-floor(log10((max - min) / (ticks - 1)))), 0);
339 340 n++;
340 341 for (int i = 0; i < ticks; i++) {
341 342 qreal value = min + (i * (max - min) / (ticks - 1));
342 343 labels << QDateTime::fromMSecsSinceEpoch(value).toString(format);
343 344 }
344 345 return labels;
345 346 }
346 347
347 348 void ChartAxisElement::axisSelected()
348 349 {
349 350 emit clicked();
350 351 }
351 352
352 353 #include "moc_chartaxiselement_p.cpp"
353 354
354 355 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,431 +1,432
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "polarchartaxisangular_p.h"
22 22 #include "chartpresenter_p.h"
23 23 #include "abstractchartlayout_p.h"
24 24 #include "qabstractaxis.h"
25 25 #include "qabstractaxis_p.h"
26 26 #include <QDebug>
27 27 #include <qmath.h>
28 28 #include <QTextDocument>
29 29
30 30 QTCOMMERCIALCHART_BEGIN_NAMESPACE
31 31
32 32 PolarChartAxisAngular::PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
33 33 : PolarChartAxis(axis, item, intervalAxis)
34 34 {
35 35 }
36 36
37 37 PolarChartAxisAngular::~PolarChartAxisAngular()
38 38 {
39 39 }
40 40
41 41 void PolarChartAxisAngular::updateGeometry()
42 42 {
43 43 QGraphicsLayoutItem::updateGeometry();
44 44
45 45 const QVector<qreal> &layout = this->layout();
46 46 if (layout.isEmpty())
47 47 return;
48 48
49 49 createAxisLabels(layout);
50 50 QStringList labelList = labels();
51 51 QPointF center = axisGeometry().center();
52 52 QList<QGraphicsItem *> arrowItemList = arrowItems();
53 53 QList<QGraphicsItem *> gridItemList = gridItems();
54 54 QList<QGraphicsItem *> labelItemList = labelItems();
55 55 QList<QGraphicsItem *> shadeItemList = shadeItems();
56 56 QGraphicsTextItem *title = titleItem();
57 57
58 58 QGraphicsEllipseItem *axisLine = static_cast<QGraphicsEllipseItem *>(arrowItemList.at(0));
59 59 axisLine->setRect(axisGeometry());
60 60
61 61 qreal radius = axisGeometry().height() / 2.0;
62 62
63 63 QRectF previousLabelRect;
64 64 QRectF firstLabelRect;
65 65
66 66 qreal labelHeight = 0;
67 67
68 68 bool firstShade = true;
69 69 bool nextTickVisible = false;
70 70 if (layout.size())
71 71 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > 360.0);
72 72
73 73 for (int i = 0; i < layout.size(); ++i) {
74 74 qreal angularCoordinate = layout.at(i);
75 75
76 76 QGraphicsLineItem *gridLineItem = static_cast<QGraphicsLineItem *>(gridItemList.at(i));
77 77 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
78 78 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
79 79 QGraphicsPathItem *shadeItem = 0;
80 80 if (i == 0)
81 81 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
82 82 else if (i % 2)
83 83 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
84 84
85 85 // Ignore ticks outside valid range
86 86 bool currentTickVisible = nextTickVisible;
87 87 if ((i == layout.size() - 1)
88 88 || layout.at(i + 1) < 0.0
89 89 || layout.at(i + 1) > 360.0) {
90 90 nextTickVisible = false;
91 91 } else {
92 92 nextTickVisible = true;
93 93 }
94 94
95 95 qreal labelCoordinate = angularCoordinate;
96 96 qreal labelVisible = currentTickVisible;
97 97 if (intervalAxis()) {
98 98 qreal farEdge;
99 99 if (i == (layout.size() - 1))
100 100 farEdge = 360.0;
101 101 else
102 102 farEdge = qMin(qreal(360.0), layout.at(i + 1));
103 103
104 104 // Adjust the labelCoordinate to show it if next tick is visible
105 105 if (nextTickVisible)
106 106 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
107 107
108 108 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
109 109 // Don't display label once the category gets too small near the axis
110 110 if (labelCoordinate < 5.0 || labelCoordinate > 355.0)
111 111 labelVisible = false;
112 112 else
113 113 labelVisible = true;
114 114 }
115 115
116 116 // Need this also in label calculations, so determine it first
117 117 QLineF tickLine(QLineF::fromPolar(radius - tickWidth(), 90.0 - angularCoordinate).p2(),
118 118 QLineF::fromPolar(radius + tickWidth(), 90.0 - angularCoordinate).p2());
119 119 tickLine.translate(center);
120 120
121 121 // Angular axis label
122 122 if (axis()->labelsVisible() && labelVisible) {
123 123 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(),
124 124 labelList.at(i),
125 125 axis()->labelsAngle());
126 126 labelItem->setTextWidth(boundingRect.width());
127 127 labelItem->setHtml(labelList.at(i));
128 128 const QRectF &rect = labelItem->boundingRect();
129 129 QPointF labelCenter = rect.center();
130 130 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
131 131 boundingRect.moveCenter(labelCenter);
132 132 QPointF positionDiff(rect.topLeft() - boundingRect.topLeft());
133 133
134 134 QPointF labelPoint;
135 135 if (intervalAxis()) {
136 136 QLineF labelLine = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate);
137 137 labelLine.translate(center);
138 138 labelPoint = labelLine.p2();
139 139 } else {
140 140 labelPoint = tickLine.p2();
141 141 }
142 142
143 143 QRectF labelRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
144 144 labelItem->setPos(labelRect.topLeft() + positionDiff);
145 145
146 146 // Store height for title calculations
147 147 qreal labelClearance = axisGeometry().top() - labelRect.top();
148 148 labelHeight = qMax(labelHeight, labelClearance);
149 149
150 150 // Label overlap detection
151 151 if (i && (previousLabelRect.intersects(labelRect) || firstLabelRect.intersects(labelRect))) {
152 152 labelVisible = false;
153 153 } else {
154 154 // Store labelRect for future comparison. Some area is deducted to make things look
155 155 // little nicer, as usually intersection happens at label corner with angular labels.
156 156 labelRect.adjust(-2.0, -4.0, -2.0, -4.0);
157 157 if (firstLabelRect.isEmpty())
158 158 firstLabelRect = labelRect;
159 159
160 160 previousLabelRect = labelRect;
161 161 labelVisible = true;
162 162 }
163 163 }
164 164
165 165 labelItem->setVisible(labelVisible);
166 166 if (!currentTickVisible) {
167 167 gridLineItem->setVisible(false);
168 168 tickItem->setVisible(false);
169 169 if (shadeItem)
170 170 shadeItem->setVisible(false);
171 171 continue;
172 172 }
173 173
174 174 // Angular grid line
175 175 QLineF gridLine = QLineF::fromPolar(radius, 90.0 - angularCoordinate);
176 176 gridLine.translate(center);
177 177 gridLineItem->setLine(gridLine);
178 178 gridLineItem->setVisible(true);
179 179
180 180 // Tick
181 181 tickItem->setLine(tickLine);
182 182 tickItem->setVisible(true);
183 183
184 184 // Shades
185 185 if (i % 2 || (i == 0 && !nextTickVisible)) {
186 186 QPainterPath path;
187 187 path.moveTo(center);
188 188 if (i == 0) {
189 189 // If first tick is also the last, we need to custom fill the first partial arc
190 190 // or it won't get filled.
191 191 path.arcTo(axisGeometry(), 90.0 - layout.at(0), layout.at(0));
192 192 path.closeSubpath();
193 193 } else {
194 194 qreal nextCoordinate;
195 195 if (!nextTickVisible) // Last visible tick
196 196 nextCoordinate = 360.0;
197 197 else
198 198 nextCoordinate = layout.at(i + 1);
199 199 qreal arcSpan = angularCoordinate - nextCoordinate;
200 200 path.arcTo(axisGeometry(), 90.0 - angularCoordinate, arcSpan);
201 201 path.closeSubpath();
202 202
203 203 // Add additional arc for first shade item if there is a partial arc to be filled
204 204 if (firstShade) {
205 205 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
206 206 if (layout.at(i - 1) > 0.0) {
207 207 QPainterPath specialPath;
208 208 specialPath.moveTo(center);
209 209 specialPath.arcTo(axisGeometry(), 90.0 - layout.at(i - 1), layout.at(i - 1));
210 210 specialPath.closeSubpath();
211 211 specialShadeItem->setPath(specialPath);
212 212 specialShadeItem->setVisible(true);
213 213 } else {
214 214 specialShadeItem->setVisible(false);
215 215 }
216 216 }
217 217 }
218 218 shadeItem->setPath(path);
219 219 shadeItem->setVisible(true);
220 220 firstShade = false;
221 221 }
222 222 }
223 223
224 224 // Title, centered above the chart
225 225 QString titleText = axis()->titleText();
226 226 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
227 227 QRectF truncatedRect;
228 228 qreal availableTitleHeight = axisGeometry().height() - labelPadding() - titlePadding() * 2.0;
229 229 qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(), "...").height();
230 230 availableTitleHeight -= minimumLabelHeight;
231 231 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
232 232 axisGeometry().width(), availableTitleHeight,
233 233 truncatedRect));
234 234 title->setTextWidth(truncatedRect.width());
235 235
236 236 QRectF titleBoundingRect = title->boundingRect();
237 237 QPointF titleCenter = center - titleBoundingRect.center();
238 238 title->setPos(titleCenter.x(), axisGeometry().top() - titlePadding() * 2.0 - titleBoundingRect.height() - labelHeight);
239 239 }
240 240 }
241 241
242 242 Qt::Orientation PolarChartAxisAngular::orientation() const
243 243 {
244 244 return Qt::Horizontal;
245 245 }
246 246
247 247 void PolarChartAxisAngular::createItems(int count)
248 248 {
249 249 if (arrowItems().count() == 0) {
250 250 // angular axis line
251 251 QGraphicsEllipseItem *arrow = new QGraphicsEllipseItem(presenter()->rootItem());
252 252 arrow->setPen(axis()->linePen());
253 253 arrowGroup()->addToGroup(arrow);
254 254 }
255 255
256 QGraphicsTextItem *title = titleItem();
257 title->setFont(axis()->titleFont());
258 title->setDefaultTextColor(axis()->titleBrush().color());
259 title->setHtml(axis()->titleText());
260
256 261 for (int i = 0; i < count; ++i) {
257 262 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
258 263 QGraphicsLineItem *grid = new QGraphicsLineItem(presenter()->rootItem());
259 264 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
260 265 label->document()->setDocumentMargin(ChartPresenter::textMargin());
261 QGraphicsTextItem *title = titleItem();
262 266 arrow->setPen(axis()->linePen());
263 267 grid->setPen(axis()->gridLinePen());
264 268 label->setFont(axis()->labelsFont());
265 269 label->setDefaultTextColor(axis()->labelsBrush().color());
266 270 label->setRotation(axis()->labelsAngle());
267 title->setFont(axis()->titleFont());
268 title->setDefaultTextColor(axis()->titleBrush().color());
269 title->setHtml(axis()->titleText());
270 271 arrowGroup()->addToGroup(arrow);
271 272 gridGroup()->addToGroup(grid);
272 273 labelGroup()->addToGroup(label);
273 274 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
274 275 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
275 276 shade->setPen(axis()->shadesPen());
276 277 shade->setBrush(axis()->shadesBrush());
277 278 shadeGroup()->addToGroup(shade);
278 279 }
279 280 }
280 281 }
281 282
282 283 void PolarChartAxisAngular::handleArrowPenChanged(const QPen &pen)
283 284 {
284 285 bool first = true;
285 286 foreach (QGraphicsItem *item, arrowItems()) {
286 287 if (first) {
287 288 first = false;
288 289 // First arrow item is the outer circle of axis
289 290 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
290 291 } else {
291 292 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
292 293 }
293 294 }
294 295 }
295 296
296 297 void PolarChartAxisAngular::handleGridPenChanged(const QPen &pen)
297 298 {
298 299 foreach (QGraphicsItem *item, gridItems())
299 300 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
300 301 }
301 302
302 303 QSizeF PolarChartAxisAngular::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
303 304 {
304 305 Q_UNUSED(which);
305 306 Q_UNUSED(constraint);
306 307 return QSizeF(-1, -1);
307 308 }
308 309
309 310 qreal PolarChartAxisAngular::preferredAxisRadius(const QSizeF &maxSize)
310 311 {
311 312 qreal radius = maxSize.height() / 2.0;
312 313 if (maxSize.width() < maxSize.height())
313 314 radius = maxSize.width() / 2.0;
314 315
315 316 if (axis()->labelsVisible()) {
316 317 QVector<qreal> layout = calculateLayout();
317 318 if (layout.isEmpty())
318 319 return radius;
319 320
320 321 createAxisLabels(layout);
321 322 QStringList labelList = labels();
322 323 QFont font = axis()->labelsFont();
323 324
324 325 QRectF maxRect;
325 326 maxRect.setSize(maxSize);
326 327 maxRect.moveCenter(QPointF(0.0, 0.0));
327 328
328 329 // This is a horrible way to find out the maximum radius for angular axis and its labels.
329 330 // It just increments the radius down until everyhing fits the constraint size.
330 331 // Proper way would be to actually calculate it but this seems to work reasonably fast as it is.
331 332 bool nextTickVisible = false;
332 333 for (int i = 0; i < layout.size(); ) {
333 334 if ((i == layout.size() - 1)
334 335 || layout.at(i + 1) < 0.0
335 336 || layout.at(i + 1) > 360.0) {
336 337 nextTickVisible = false;
337 338 } else {
338 339 nextTickVisible = true;
339 340 }
340 341
341 342 qreal labelCoordinate = layout.at(i);
342 343 qreal labelVisible;
343 344
344 345 if (intervalAxis()) {
345 346 qreal farEdge;
346 347 if (i == (layout.size() - 1))
347 348 farEdge = 360.0;
348 349 else
349 350 farEdge = qMin(qreal(360.0), layout.at(i + 1));
350 351
351 352 // Adjust the labelCoordinate to show it if next tick is visible
352 353 if (nextTickVisible)
353 354 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
354 355
355 356 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
356 357 }
357 358
358 359 if (labelCoordinate < 0.0 || labelCoordinate > 360.0)
359 360 labelVisible = false;
360 361 else
361 362 labelVisible = true;
362 363
363 364 if (!labelVisible) {
364 365 i++;
365 366 continue;
366 367 }
367 368
368 369 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
369 370 QPointF labelPoint = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate).p2();
370 371
371 372 boundingRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
372 373 QRectF intersectRect = maxRect.intersected(boundingRect);
373 374 if (boundingRect.isEmpty() || intersectRect == boundingRect) {
374 375 i++;
375 376 } else {
376 377 qreal reduction(0.0);
377 378 // If there is no intersection, reduce by smallest dimension of label rect to be on the safe side
378 379 if (intersectRect.isEmpty()) {
379 380 reduction = qMin(boundingRect.height(), boundingRect.width());
380 381 } else {
381 382 // Approximate needed radius reduction is the amount label rect exceeds max rect in either dimension.
382 383 // Could be further optimized by figuring out the proper math how to calculate exact needed reduction.
383 384 reduction = qMax(boundingRect.height() - intersectRect.height(),
384 385 boundingRect.width() - intersectRect.width());
385 386 }
386 387 // Typically the approximated reduction is little low, so add one
387 388 radius -= (reduction + 1.0);
388 389
389 390 if (radius < 1.0) // safeguard
390 391 return 1.0;
391 392 }
392 393 }
393 394 }
394 395
395 396 if (!axis()->titleText().isEmpty() && axis()->isTitleVisible()) {
396 397 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
397 398
398 399 radius -= titlePadding() + (titleRect.height() / 2.0);
399 400 if (radius < 1.0) // safeguard
400 401 return 1.0;
401 402 }
402 403
403 404 return radius;
404 405 }
405 406
406 407 QRectF PolarChartAxisAngular::moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const
407 408 {
408 409 if (angularCoordinate == 0.0)
409 410 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
410 411 else if (angularCoordinate < 90.0)
411 412 labelRect.moveBottomLeft(labelPoint);
412 413 else if (angularCoordinate == 90.0)
413 414 labelRect.moveCenter(labelPoint + QPointF(labelRect.width() / 2.0 + 2.0, 0)); // +2 so that it does not hit the radial axis
414 415 else if (angularCoordinate < 180.0)
415 416 labelRect.moveTopLeft(labelPoint);
416 417 else if (angularCoordinate == 180.0)
417 418 labelRect.moveCenter(labelPoint + QPointF(0, labelRect.height() / 2.0));
418 419 else if (angularCoordinate < 270.0)
419 420 labelRect.moveTopRight(labelPoint);
420 421 else if (angularCoordinate == 270.0)
421 422 labelRect.moveCenter(labelPoint + QPointF(-labelRect.width() / 2.0 - 2.0, 0)); // -2 so that it does not hit the radial axis
422 423 else if (angularCoordinate < 360.0)
423 424 labelRect.moveBottomRight(labelPoint);
424 425 else
425 426 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
426 427 return labelRect;
427 428 }
428 429
429 430 #include "moc_polarchartaxisangular_p.cpp"
430 431
431 432 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,296 +1,297
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Enterprise Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Enterprise licenses may use this file in
11 11 ** accordance with the Qt Enterprise License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "polarchartaxisradial_p.h"
22 22 #include "chartpresenter_p.h"
23 23 #include "abstractchartlayout_p.h"
24 24 #include "qabstractaxis_p.h"
25 25 #include "linearrowitem_p.h"
26 26 #include <QTextDocument>
27 27
28 28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
29 29
30 30 PolarChartAxisRadial::PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
31 31 : PolarChartAxis(axis, item, intervalAxis)
32 32 {
33 33 }
34 34
35 35 PolarChartAxisRadial::~PolarChartAxisRadial()
36 36 {
37 37 }
38 38
39 39 void PolarChartAxisRadial::updateGeometry()
40 40 {
41 41 const QVector<qreal> &layout = this->layout();
42 42 if (layout.isEmpty())
43 43 return;
44 44
45 45 createAxisLabels(layout);
46 46 QStringList labelList = labels();
47 47 QPointF center = axisGeometry().center();
48 48 QList<QGraphicsItem *> arrowItemList = arrowItems();
49 49 QList<QGraphicsItem *> gridItemList = gridItems();
50 50 QList<QGraphicsItem *> labelItemList = labelItems();
51 51 QList<QGraphicsItem *> shadeItemList = shadeItems();
52 52 QGraphicsTextItem* title = titleItem();
53 53 qreal radius = axisGeometry().height() / 2.0;
54 54
55 55 QLineF line(center, center + QPointF(0, -radius));
56 56 QGraphicsLineItem *axisLine = static_cast<QGraphicsLineItem *>(arrowItemList.at(0));
57 57 axisLine->setLine(line);
58 58
59 59 QRectF previousLabelRect;
60 60 bool firstShade = true;
61 61 bool nextTickVisible = false;
62 62 if (layout.size())
63 63 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > radius);
64 64
65 65 for (int i = 0; i < layout.size(); ++i) {
66 66 qreal radialCoordinate = layout.at(i);
67 67
68 68 QGraphicsEllipseItem *gridItem = static_cast<QGraphicsEllipseItem *>(gridItemList.at(i));
69 69 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
70 70 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
71 71 QGraphicsPathItem *shadeItem = 0;
72 72 if (i == 0)
73 73 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
74 74 else if (i % 2)
75 75 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
76 76
77 77 // Ignore ticks outside valid range
78 78 bool currentTickVisible = nextTickVisible;
79 79 if ((i == layout.size() - 1)
80 80 || layout.at(i + 1) < 0.0
81 81 || layout.at(i + 1) > radius) {
82 82 nextTickVisible = false;
83 83 } else {
84 84 nextTickVisible = true;
85 85 }
86 86
87 87 qreal labelCoordinate = radialCoordinate;
88 88 qreal labelVisible = currentTickVisible;
89 89 qreal labelPad = labelPadding() / 2.0;
90 90 if (intervalAxis()) {
91 91 qreal farEdge;
92 92 if (i == (layout.size() - 1))
93 93 farEdge = radius;
94 94 else
95 95 farEdge = qMin(radius, layout.at(i + 1));
96 96
97 97 // Adjust the labelCoordinate to show it if next tick is visible
98 98 if (nextTickVisible)
99 99 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
100 100
101 101 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
102 102 if (labelCoordinate > 0.0 && labelCoordinate < radius)
103 103 labelVisible = true;
104 104 else
105 105 labelVisible = false;
106 106 }
107 107
108 108 // Radial axis label
109 109 if (axis()->labelsVisible() && labelVisible) {
110 110 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(),
111 111 labelList.at(i),
112 112 axis()->labelsAngle());
113 113 labelItem->setTextWidth(boundingRect.width());
114 114 labelItem->setHtml(labelList.at(i));
115 115 QRectF labelRect = labelItem->boundingRect();
116 116 QPointF labelCenter = labelRect.center();
117 117 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
118 118 boundingRect.moveCenter(labelCenter);
119 119 QPointF positionDiff(labelRect.topLeft() - boundingRect.topLeft());
120 120 QPointF labelPoint = center;
121 121 if (intervalAxis())
122 122 labelPoint += QPointF(labelPad, -labelCoordinate - (boundingRect.height() / 2.0));
123 123 else
124 124 labelPoint += QPointF(labelPad, labelPad - labelCoordinate);
125 125 labelRect.moveTopLeft(labelPoint);
126 126 labelItem->setPos(labelRect.topLeft() + positionDiff);
127 127
128 128 // Label overlap detection
129 129 labelRect.setSize(boundingRect.size());
130 130 if ((i && previousLabelRect.intersects(labelRect))
131 131 || !axisGeometry().contains(labelRect)) {
132 132 labelVisible = false;
133 133 } else {
134 134 previousLabelRect = labelRect;
135 135 labelVisible = true;
136 136 }
137 137 }
138 138
139 139 labelItem->setVisible(labelVisible);
140 140 if (!currentTickVisible) {
141 141 gridItem->setVisible(false);
142 142 tickItem->setVisible(false);
143 143 if (shadeItem)
144 144 shadeItem->setVisible(false);
145 145 continue;
146 146 }
147 147
148 148 // Radial grid line
149 149 QRectF gridRect;
150 150 gridRect.setWidth(radialCoordinate * 2.0);
151 151 gridRect.setHeight(radialCoordinate * 2.0);
152 152 gridRect.moveCenter(center);
153 153
154 154 gridItem->setRect(gridRect);
155 155 gridItem->setVisible(true);
156 156
157 157 // Tick
158 158 QLineF tickLine(-tickWidth(), 0.0, tickWidth(), 0.0);
159 159 tickLine.translate(center.rx(), gridRect.top());
160 160 tickItem->setLine(tickLine);
161 161 tickItem->setVisible(true);
162 162
163 163 // Shades
164 164 if (i % 2 || (i == 0 && !nextTickVisible)) {
165 165 QPainterPath path;
166 166 if (i == 0) {
167 167 // If first tick is also the last, we need to custom fill the inner circle
168 168 // or it won't get filled.
169 169 QRectF innerCircle(0.0, 0.0, layout.at(0) * 2.0, layout.at(0) * 2.0);
170 170 innerCircle.moveCenter(center);
171 171 path.addEllipse(innerCircle);
172 172 } else {
173 173 QRectF otherGridRect;
174 174 if (!nextTickVisible) { // Last visible tick
175 175 otherGridRect = axisGeometry();
176 176 } else {
177 177 qreal otherGridRectDimension = layout.at(i + 1) * 2.0;
178 178 otherGridRect.setWidth(otherGridRectDimension);
179 179 otherGridRect.setHeight(otherGridRectDimension);
180 180 otherGridRect.moveCenter(center);
181 181 }
182 182 path.addEllipse(gridRect);
183 183 path.addEllipse(otherGridRect);
184 184
185 185 // Add additional shading in first visible shade item if there is a partial tick
186 186 // to be filled at the center (log & category axes)
187 187 if (firstShade) {
188 188 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
189 189 if (layout.at(i - 1) > 0.0) {
190 190 QRectF innerCircle(0.0, 0.0, layout.at(i - 1) * 2.0, layout.at(i - 1) * 2.0);
191 191 innerCircle.moveCenter(center);
192 192 QPainterPath specialPath;
193 193 specialPath.addEllipse(innerCircle);
194 194 specialShadeItem->setPath(specialPath);
195 195 specialShadeItem->setVisible(true);
196 196 } else {
197 197 specialShadeItem->setVisible(false);
198 198 }
199 199 }
200 200 }
201 201 shadeItem->setPath(path);
202 202 shadeItem->setVisible(true);
203 203 firstShade = false;
204 204 }
205 205 }
206 206
207 207 // Title, along the 0 axis
208 208 QString titleText = axis()->titleText();
209 209 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
210 210 QRectF truncatedRect;
211 211 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
212 212 radius, radius, truncatedRect));
213 213 title->setTextWidth(truncatedRect.width());
214 214
215 215 QRectF titleBoundingRect = title->boundingRect();
216 216 QPointF titleCenter = titleBoundingRect.center();
217 217 QPointF arrowCenter = axisLine->boundingRect().center();
218 218 QPointF titleCenterDiff = arrowCenter - titleCenter;
219 219 title->setPos(titleCenterDiff.x() - titlePadding() - (titleBoundingRect.height() / 2.0), titleCenterDiff.y());
220 220 title->setTransformOriginPoint(titleCenter);
221 221 title->setRotation(270.0);
222 222 }
223 223
224 224 QGraphicsLayoutItem::updateGeometry();
225 225 }
226 226
227 227 Qt::Orientation PolarChartAxisRadial::orientation() const
228 228 {
229 229 return Qt::Vertical;
230 230 }
231 231
232 232 void PolarChartAxisRadial::createItems(int count)
233 233 {
234 234 if (arrowItems().count() == 0) {
235 235 // radial axis center line
236 236 QGraphicsLineItem *arrow = new LineArrowItem(this, presenter()->rootItem());
237 237 arrow->setPen(axis()->linePen());
238 238 arrowGroup()->addToGroup(arrow);
239 239 }
240 240
241 QGraphicsTextItem *title = titleItem();
242 title->setFont(axis()->titleFont());
243 title->setDefaultTextColor(axis()->titleBrush().color());
244 title->setHtml(axis()->titleText());
245
241 246 for (int i = 0; i < count; ++i) {
242 247 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
243 248 QGraphicsEllipseItem *grid = new QGraphicsEllipseItem(presenter()->rootItem());
244 249 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
245 250 label->document()->setDocumentMargin(ChartPresenter::textMargin());
246 QGraphicsTextItem *title = titleItem();
247 251 arrow->setPen(axis()->linePen());
248 252 grid->setPen(axis()->gridLinePen());
249 253 label->setFont(axis()->labelsFont());
250 254 label->setDefaultTextColor(axis()->labelsBrush().color());
251 255 label->setRotation(axis()->labelsAngle());
252 title->setFont(axis()->titleFont());
253 title->setDefaultTextColor(axis()->titleBrush().color());
254 title->setHtml(axis()->titleText());
255 256 arrowGroup()->addToGroup(arrow);
256 257 gridGroup()->addToGroup(grid);
257 258 labelGroup()->addToGroup(label);
258 259 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
259 260 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
260 261 shade->setPen(axis()->shadesPen());
261 262 shade->setBrush(axis()->shadesBrush());
262 263 shadeGroup()->addToGroup(shade);
263 264 }
264 265 }
265 266 }
266 267
267 268 void PolarChartAxisRadial::handleArrowPenChanged(const QPen &pen)
268 269 {
269 270 foreach (QGraphicsItem *item, arrowItems())
270 271 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
271 272 }
272 273
273 274 void PolarChartAxisRadial::handleGridPenChanged(const QPen &pen)
274 275 {
275 276 foreach (QGraphicsItem *item, gridItems())
276 277 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
277 278 }
278 279
279 280 QSizeF PolarChartAxisRadial::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
280 281 {
281 282 Q_UNUSED(which);
282 283 Q_UNUSED(constraint);
283 284 return QSizeF(-1.0, -1.0);
284 285 }
285 286
286 287 qreal PolarChartAxisRadial::preferredAxisRadius(const QSizeF &maxSize)
287 288 {
288 289 qreal radius = maxSize.height() / 2.0;
289 290 if (maxSize.width() < maxSize.height())
290 291 radius = maxSize.width() / 2.0;
291 292 return radius;
292 293 }
293 294
294 295 #include "moc_polarchartaxisradial_p.cpp"
295 296
296 297 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now