##// END OF EJS Templates
Fix category axis shades and labels...
Titta Heikkala -
r2760:a803e4e9381b
parent child
Show More
@@ -1,244 +1,247
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2014 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.io
6 6 **
7 7 ** This file is part of the Qt Charts module.
8 8 **
9 9 ** Licensees holding valid commercial license for Qt may use this file in
10 10 ** accordance with the Qt License Agreement provided with the Software
11 11 ** or, alternatively, in accordance with the terms contained in a written
12 12 ** agreement between you and Digia.
13 13 **
14 14 ** If you have questions regarding the use of this file, please use
15 15 ** contact form at http://qt.io
16 16 **
17 17 ****************************************************************************/
18 18
19 19 #include <private/horizontalaxis_p.h>
20 20 #include <private/qabstractaxis_p.h>
21 21 #include <private/chartpresenter_p.h>
22 22 #include <QtCore/QtMath>
23 23 #include <QtCore/QDebug>
24 24
25 25 QT_CHARTS_BEGIN_NAMESPACE
26 26
27 27 HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
28 28 : CartesianChartAxis(axis, item, intervalAxis)
29 29 {
30 30 }
31 31
32 32 HorizontalAxis::~HorizontalAxis()
33 33 {
34 34 }
35 35
36 36 void HorizontalAxis::updateGeometry()
37 37 {
38 38 const QVector<qreal> &layout = ChartAxisElement::layout();
39 39
40 40 if (layout.isEmpty() && axis()->type() != QAbstractAxis::AxisTypeLogValue)
41 41 return;
42 42
43 43 QStringList labelList = labels();
44 44
45 45 QList<QGraphicsItem *> labels = labelItems();
46 46 QList<QGraphicsItem *> arrow = arrowItems();
47 47 QGraphicsTextItem *title = titleItem();
48 48
49 49 Q_ASSERT(labels.size() == labelList.size());
50 50 Q_ASSERT(layout.size() == labelList.size());
51 51
52 52 const QRectF &axisRect = axisGeometry();
53 53 const QRectF &gridRect = gridGeometry();
54 54
55 55 //arrow
56 56 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(arrow.at(0));
57 57
58 58 if (axis()->alignment() == Qt::AlignTop)
59 59 arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom());
60 60 else if (axis()->alignment() == Qt::AlignBottom)
61 61 arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
62 62
63 63 qreal width = 0;
64 64 const QLatin1String ellipsis("...");
65 65
66 66 //title
67 67 QRectF titleBoundingRect;
68 68 QString titleText = axis()->titleText();
69 69 qreal availableSpace = axisRect.height() - labelPadding();
70 70 if (!titleText.isEmpty() && titleItem()->isVisible()) {
71 71 availableSpace -= titlePadding() * 2.0;
72 72 qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(),
73 73 QStringLiteral("...")).height();
74 74 qreal titleSpace = availableSpace - minimumLabelHeight;
75 75 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
76 76 gridRect.width(), titleSpace,
77 77 titleBoundingRect));
78 78 title->setTextWidth(titleBoundingRect.width());
79 79
80 80 titleBoundingRect = title->boundingRect();
81 81
82 82 QPointF center = gridRect.center() - titleBoundingRect.center();
83 83 if (axis()->alignment() == Qt::AlignTop)
84 84 title->setPos(center.x(), axisRect.top() + titlePadding());
85 85 else if (axis()->alignment() == Qt::AlignBottom)
86 86 title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePadding());
87 87
88 88 availableSpace -= titleBoundingRect.height();
89 89 }
90 90
91 91 if (layout.isEmpty() && axis()->type() == QAbstractAxis::AxisTypeLogValue)
92 92 return;
93 93
94 94 QList<QGraphicsItem *> lines = gridItems();
95 95 QList<QGraphicsItem *> shades = shadeItems();
96 96
97 97 for (int i = 0; i < layout.size(); ++i) {
98 98 //items
99 99 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem*>(lines.at(i));
100 100 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(arrow.at(i + 1));
101 101 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
102 102
103 103 //grid line
104 104 gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom());
105 105
106 106 //label text wrapping
107 107 QString text = labelList.at(i);
108 108 QRectF boundingRect;
109 109 // don't truncate empty labels
110 110 if (text.isEmpty()) {
111 111 labelItem->setHtml(text);
112 112 } else {
113 113 qreal labelWidth = axisRect.width() / layout.count() - (2 * labelPadding());
114 114 QString truncatedText = ChartPresenter::truncatedText(axis()->labelsFont(), text,
115 115 axis()->labelsAngle(),
116 116 labelWidth,
117 117 availableSpace, boundingRect);
118 118 labelItem->setTextWidth(ChartPresenter::textBoundingRect(axis()->labelsFont(),
119 119 truncatedText).width());
120 120 labelItem->setHtml(truncatedText);
121 121 }
122 122
123 123 //label transformation origin point
124 124 const QRectF& rect = labelItem->boundingRect();
125 125 QPointF center = rect.center();
126 126 labelItem->setTransformOriginPoint(center.x(), center.y());
127 127 qreal heightDiff = rect.height() - boundingRect.height();
128 128 qreal widthDiff = rect.width() - boundingRect.width();
129 129
130 130 //ticks and label position
131 131 if (axis()->alignment() == Qt::AlignTop) {
132 132 labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height() + (heightDiff / 2.0) - labelPadding());
133 133 tickItem->setLine(layout[i], axisRect.bottom(), layout[i], axisRect.bottom() - labelPadding());
134 134 } else if (axis()->alignment() == Qt::AlignBottom) {
135 135 labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2.0) + labelPadding());
136 136 tickItem->setLine(layout[i], axisRect.top(), layout[i], axisRect.top() + labelPadding());
137 137 }
138 138
139 139 //label in between
140 140 bool forceHide = false;
141 141 if (intervalAxis() && (i + 1) != layout.size()) {
142 142 qreal leftBound = qMax(layout[i], gridRect.left());
143 143 qreal rightBound = qMin(layout[i + 1], gridRect.right());
144 144 const qreal delta = rightBound - leftBound;
145 145 // Hide label in case visible part of the category at the grid edge is too narrow
146 146 if (delta < boundingRect.width()
147 && (leftBound == gridRect.left() || rightBound == gridRect.right())
148 && !intervalAxis()) {
147 && (leftBound == gridRect.left() || rightBound == gridRect.right())) {
149 148 forceHide = true;
150 149 } else {
151 150 labelItem->setPos(leftBound + (delta / 2.0) - center.x(), labelItem->pos().y());
152 151 }
153 152 }
154 153
155 154 //label overlap detection - compensate one pixel for rounding errors
156 155 if ((labelItem->pos().x() < width && labelItem->toPlainText() == ellipsis) || forceHide ||
157 156 (labelItem->pos().x() + (widthDiff / 2.0)) < (axisRect.left() - 1.0) ||
158 157 (labelItem->pos().x() + (widthDiff / 2.0) - 1.0) > axisRect.right()) {
159 158 labelItem->setVisible(false);
160 159 } else {
161 160 labelItem->setVisible(true);
162 161 width = boundingRect.width() + labelItem->pos().x();
163 162 }
164 163
165 164 //shades
166 165 QGraphicsRectItem *shadeItem = 0;
167 166 if (i == 0)
168 167 shadeItem = static_cast<QGraphicsRectItem *>(shades.at(0));
169 168 else if (i % 2)
170 169 shadeItem = static_cast<QGraphicsRectItem *>(shades.at((i / 2) + 1));
171 170 if (shadeItem) {
172 171 qreal leftBound;
173 172 qreal rightBound;
174 173 if (i == 0) {
175 174 leftBound = gridRect.left();
176 175 rightBound = layout[0];
177 176 } else {
178 177 leftBound = layout[i];
179 178 if (i == layout.size() - 1)
180 179 rightBound = gridRect.right();
181 180 else
182 181 rightBound = qMin(layout[i + 1], gridRect.right());
183 182 }
183 if (leftBound < gridRect.left())
184 leftBound = gridRect.left();
185 if (rightBound > gridRect.right())
186 rightBound = gridRect.right();
184 187 shadeItem->setRect(leftBound, gridRect.top(), rightBound - leftBound,
185 188 gridRect.height());
186 189 if (shadeItem->rect().width() <= 0.0)
187 190 shadeItem->setVisible(false);
188 191 else
189 192 shadeItem->setVisible(true);
190 193 }
191 194
192 195 // check if the grid line and the axis tick should be shown
193 196 qreal x = gridItem->line().p1().x();
194 197 if (x < gridRect.left() || x > gridRect.right()) {
195 198 gridItem->setVisible(false);
196 199 tickItem->setVisible(false);
197 200 } else {
198 201 gridItem->setVisible(true);
199 202 tickItem->setVisible(true);
200 203 }
201 204
202 205 }
203 206
204 207 //begin/end grid line in case labels between
205 208 if (intervalAxis()) {
206 209 QGraphicsLineItem *gridLine;
207 210 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
208 211 gridLine->setLine(gridRect.right(), gridRect.top(), gridRect.right(), gridRect.bottom());
209 212 gridLine->setVisible(true);
210 213 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
211 214 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.left(), gridRect.bottom());
212 215 gridLine->setVisible(true);
213 216 }
214 217 }
215 218
216 219 QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
217 220 {
218 221 Q_UNUSED(constraint);
219 222 QSizeF sh(0,0);
220 223
221 224 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
222 225 return sh;
223 226
224 227 switch (which) {
225 228 case Qt::MinimumSize: {
226 229 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(),
227 230 QStringLiteral("..."));
228 231 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
229 232 break;
230 233 }
231 234 case Qt::MaximumSize:
232 235 case Qt::PreferredSize: {
233 236 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
234 237 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
235 238 break;
236 239 }
237 240 default:
238 241 break;
239 242 }
240 243
241 244 return sh;
242 245 }
243 246
244 247 QT_CHARTS_END_NAMESPACE
@@ -1,248 +1,251
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2014 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.io
6 6 **
7 7 ** This file is part of the Qt Charts module.
8 8 **
9 9 ** Licensees holding valid commercial license for Qt may use this file in
10 10 ** accordance with the Qt License Agreement provided with the Software
11 11 ** or, alternatively, in accordance with the terms contained in a written
12 12 ** agreement between you and Digia.
13 13 **
14 14 ** If you have questions regarding the use of this file, please use
15 15 ** contact form at http://qt.io
16 16 **
17 17 ****************************************************************************/
18 18
19 19 #include <private/verticalaxis_p.h>
20 20 #include <QtCharts/QAbstractAxis>
21 21 #include <private/chartpresenter_p.h>
22 22 #include <QtCore/QDebug>
23 23
24 24 QT_CHARTS_BEGIN_NAMESPACE
25 25
26 26 VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
27 27 : CartesianChartAxis(axis, item, intervalAxis)
28 28 {
29 29 }
30 30
31 31 VerticalAxis::~VerticalAxis()
32 32 {
33 33 }
34 34
35 35 void VerticalAxis::updateGeometry()
36 36 {
37 37 const QVector<qreal> &layout = ChartAxisElement::layout();
38 38
39 39 if (layout.isEmpty() && axis()->type() != QAbstractAxis::AxisTypeLogValue)
40 40 return;
41 41
42 42 QStringList labelList = labels();
43 43
44 44 QList<QGraphicsItem *> labels = labelItems();
45 45 QList<QGraphicsItem *> arrow = arrowItems();
46 46 QGraphicsTextItem *title = titleItem();
47 47
48 48 Q_ASSERT(labels.size() == labelList.size());
49 49 Q_ASSERT(layout.size() == labelList.size());
50 50
51 51 const QRectF &axisRect = axisGeometry();
52 52 const QRectF &gridRect = gridGeometry();
53 53
54 54 qreal height = axisRect.bottom();
55 55
56 56 //arrow
57 57 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(arrow.at(0));
58 58
59 59 //arrow position
60 60 if (axis()->alignment() == Qt::AlignLeft)
61 61 arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom());
62 62 else if (axis()->alignment() == Qt::AlignRight)
63 63 arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom());
64 64
65 65 //title
66 66 QRectF titleBoundingRect;
67 67 QString titleText = axis()->titleText();
68 68 qreal availableSpace = axisRect.width() - labelPadding();
69 69 if (!titleText.isEmpty() && titleItem()->isVisible()) {
70 70 availableSpace -= titlePadding() * 2.0;
71 71 qreal minimumLabelWidth = ChartPresenter::textBoundingRect(axis()->labelsFont(),
72 72 QStringLiteral("...")).width();
73 73 qreal titleSpace = availableSpace - minimumLabelWidth;
74 74 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(90.0),
75 75 titleSpace, gridRect.height(),
76 76 titleBoundingRect));
77 77 title->setTextWidth(titleBoundingRect.height());
78 78
79 79 titleBoundingRect = title->boundingRect();
80 80
81 81 QPointF center = gridRect.center() - titleBoundingRect.center();
82 82 if (axis()->alignment() == Qt::AlignLeft)
83 83 title->setPos(axisRect.left() - titleBoundingRect.width() / 2.0 + titleBoundingRect.height() / 2.0 + titlePadding(), center.y());
84 84 else if (axis()->alignment() == Qt::AlignRight)
85 85 title->setPos(axisRect.right() - titleBoundingRect.width() / 2.0 - titleBoundingRect.height() / 2.0 - titlePadding(), center.y());
86 86
87 87 title->setTransformOriginPoint(titleBoundingRect.center());
88 88 title->setRotation(270);
89 89
90 90 availableSpace -= titleBoundingRect.height();
91 91 }
92 92
93 93 if (layout.isEmpty() && axis()->type() == QAbstractAxis::AxisTypeLogValue)
94 94 return;
95 95
96 96 QList<QGraphicsItem *> lines = gridItems();
97 97 QList<QGraphicsItem *> shades = shadeItems();
98 98
99 99 for (int i = 0; i < layout.size(); ++i) {
100 100 //items
101 101 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i));
102 102 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrow.at(i + 1));
103 103 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
104 104
105 105 //grid line
106 106 gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
107 107
108 108 //label text wrapping
109 109 QString text = labelList.at(i);
110 110 QRectF boundingRect;
111 111 // don't truncate empty labels
112 112 if (text.isEmpty()) {
113 113 labelItem->setHtml(text);
114 114 } else {
115 115 qreal labelHeight = (axisRect.height() / layout.count()) - (2 * labelPadding());
116 116 QString truncatedText = ChartPresenter::truncatedText(axis()->labelsFont(), text,
117 117 axis()->labelsAngle(),
118 118 availableSpace,
119 119 labelHeight, boundingRect);
120 120 labelItem->setTextWidth(ChartPresenter::textBoundingRect(axis()->labelsFont(),
121 121 truncatedText).width());
122 122 labelItem->setHtml(truncatedText);
123 123 }
124 124
125 125 //label transformation origin point
126 126 const QRectF &rect = labelItem->boundingRect();
127 127 QPointF center = rect.center();
128 128 labelItem->setTransformOriginPoint(center.x(), center.y());
129 129 qreal widthDiff = rect.width() - boundingRect.width();
130 130 qreal heightDiff = rect.height() - boundingRect.height();
131 131
132 132 //ticks and label position
133 133 if (axis()->alignment() == Qt::AlignLeft) {
134 134 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0) - labelPadding(), layout[i] - center.y());
135 135 tickItem->setLine(axisRect.right() - labelPadding(), layout[i], axisRect.right(), layout[i]);
136 136 } else if (axis()->alignment() == Qt::AlignRight) {
137 137 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0), layout[i] - center.y());
138 138 tickItem->setLine(axisRect.left(), layout[i], axisRect.left() + labelPadding(), layout[i]);
139 139 }
140 140
141 141 //label in between
142 142 bool forceHide = false;
143 143 if (intervalAxis() && (i + 1) != layout.size()) {
144 144 qreal lowerBound = qMin(layout[i], gridRect.bottom());
145 145 qreal upperBound = qMax(layout[i + 1], gridRect.top());
146 146 const qreal delta = lowerBound - upperBound;
147 147 // Hide label in case visible part of the category at the grid edge is too narrow
148 148 if (delta < boundingRect.height()
149 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())
150 && !intervalAxis()) {
149 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())) {
151 150 forceHide = true;
152 151 } else {
153 152 labelItem->setPos(labelItem->pos().x() , lowerBound - (delta / 2.0) - center.y());
154 153 }
155 154 }
156 155
157 156 //label overlap detection - compensate one pixel for rounding errors
158 157 if (labelItem->pos().y() + boundingRect.height() > height || forceHide ||
159 158 (labelItem->pos().y() + (heightDiff / 2.0) - 1.0) > axisRect.bottom() ||
160 159 labelItem->pos().y() + (heightDiff / 2.0) < (axisRect.top() - 1.0)) {
161 160 labelItem->setVisible(false);
162 161 }
163 162 else {
164 163 labelItem->setVisible(true);
165 164 height=labelItem->pos().y();
166 165 }
167 166
168 167 //shades
169 168 QGraphicsRectItem *shadeItem = 0;
170 169 if (i == 0)
171 170 shadeItem = static_cast<QGraphicsRectItem *>(shades.at(0));
172 171 else if (i % 2)
173 172 shadeItem = static_cast<QGraphicsRectItem *>(shades.at((i / 2) + 1));
174 173 if (shadeItem) {
175 174 qreal lowerBound;
176 175 qreal upperBound;
177 176 if (i == 0) {
178 177 lowerBound = gridRect.bottom();
179 178 upperBound = layout[0];
180 179 } else {
181 180 lowerBound = layout[i];
182 181 if (i == layout.size() - 1)
183 182 upperBound = gridRect.top();
184 183 else
185 184 upperBound = qMax(layout[i + 1], gridRect.top());
186 185
187 186 }
187 if (lowerBound > gridRect.bottom())
188 lowerBound = gridRect.bottom();
189 if (upperBound < gridRect.top())
190 upperBound = gridRect.top();
188 191 shadeItem->setRect(gridRect.left(), upperBound, gridRect.width(),
189 192 lowerBound - upperBound);
190 193 if (shadeItem->rect().height() <= 0.0)
191 194 shadeItem->setVisible(false);
192 195 else
193 196 shadeItem->setVisible(true);
194 197 }
195 198
196 199 // check if the grid line and the axis tick should be shown
197 200 qreal y = gridItem->line().p1().y();
198 201 if ((y < gridRect.top() || y > gridRect.bottom()))
199 202 {
200 203 gridItem->setVisible(false);
201 204 tickItem->setVisible(false);
202 205 }else{
203 206 gridItem->setVisible(true);
204 207 tickItem->setVisible(true);
205 208 }
206 209
207 210 }
208 211 //begin/end grid line in case labels between
209 212 if (intervalAxis()) {
210 213 QGraphicsLineItem *gridLine;
211 214 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
212 215 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
213 216 gridLine->setVisible(true);
214 217 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size() + 1));
215 218 gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
216 219 gridLine->setVisible(true);
217 220 }
218 221 }
219 222
220 223 QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
221 224 {
222 225 Q_UNUSED(constraint);
223 226 QSizeF sh(0, 0);
224 227
225 228 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
226 229 return sh;
227 230
228 231 switch (which) {
229 232 case Qt::MinimumSize: {
230 233 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(),
231 234 QStringLiteral("..."));
232 235 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
233 236 break;
234 237 }
235 238 case Qt::MaximumSize:
236 239 case Qt::PreferredSize: {
237 240 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
238 241 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
239 242 break;
240 243 }
241 244 default:
242 245 break;
243 246 }
244 247
245 248 return sh;
246 249 }
247 250
248 251 QT_CHARTS_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now