##// END OF EJS Templates
Compensate for rounding errors when determining label visibility...
Miikka Heikkinen -
r2445:825c77a81d31
parent child
Show More
@@ -1,209 +1,209
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 Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial 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 "horizontalaxis_p.h"
22 22 #include "qabstractaxis.h"
23 23 #include <QFontMetrics>
24 24 #include <qmath.h>
25 25 #include <QDebug>
26 26
27 27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 28
29 29 HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem* item , bool intervalAxis)
30 30 : ChartAxis(axis, item, intervalAxis)
31 31 {
32 32 }
33 33
34 34 HorizontalAxis::~HorizontalAxis()
35 35 {
36 36 }
37 37
38 38 void HorizontalAxis::updateGeometry()
39 39 {
40 40 const QVector<qreal>& layout = ChartAxis::layout();
41 41
42 42 if (layout.isEmpty())
43 43 return;
44 44
45 45 QStringList labelList = labels();
46 46
47 47 QList<QGraphicsItem *> lines = lineItems();
48 48 QList<QGraphicsItem *> labels = labelItems();
49 49 QList<QGraphicsItem *> shades = shadeItems();
50 50 QList<QGraphicsItem *> axis = arrowItems();
51 51 QGraphicsSimpleTextItem* title = titleItem();
52 52
53 53 Q_ASSERT(labels.size() == labelList.size());
54 54 Q_ASSERT(layout.size() == labelList.size());
55 55
56 56 const QRectF &axisRect = axisGeometry();
57 57 const QRectF &gridRect = gridGeometry();
58 58
59 59 //arrow
60 60 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(axis.at(0));
61 61
62 62 if (alignment() == Qt::AlignTop)
63 63 arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom());
64 64 else if (alignment() == Qt::AlignBottom)
65 65 arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
66 66
67 67 qreal width = 0;
68 68 QFontMetrics fn(font());
69 69
70 70 //title
71 71 int titlePad = 0;
72 72 QRectF titleBoundingRect;
73 73 if (!titleText().isEmpty() && titleItem()->isVisible()) {
74 74 QFontMetrics fn(title->font());
75 75 int size(0);
76 76 size = gridRect.width();
77 77 QString titleText = this->titleText();
78 78
79 79 if (fn.boundingRect(titleText).width() > size) {
80 80 QString string = titleText + "...";
81 81 while (fn.boundingRect(string).width() > size && string.length() > 3)
82 82 string.remove(string.length() - 4, 1);
83 83 title->setText(string);
84 84 } else {
85 85 title->setText(titleText);
86 86 }
87 87
88 88 titlePad = titlePadding();
89 89 titleBoundingRect = title->boundingRect();
90 90
91 91 QPointF center = gridRect.center() - titleBoundingRect.center();
92 92 if (alignment() == Qt::AlignTop) {
93 93 title->setPos(center.x(), axisRect.top() + titlePad);
94 94 } else if (alignment() == Qt::AlignBottom) {
95 95 title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePad);
96 96 }
97 97 }
98 98
99 99 for (int i = 0; i < layout.size(); ++i) {
100 100
101 101 //items
102 102 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem*>(lines.at(i));
103 103 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(axis.at(i + 1));
104 104 QGraphicsSimpleTextItem *labelItem = static_cast<QGraphicsSimpleTextItem *>(labels.at(i));
105 105
106 106 //grid line
107 107 gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom());
108 108
109 109 //label text wrapping
110 110 QString text = labelList.at(i);
111 111 QRectF boundingRect = labelBoundingRect(fn, text);
112 112 qreal size = axisRect.bottom() - axisRect.top() - labelPadding() - titleBoundingRect.height() - (titlePad * 2);
113 113 if (boundingRect.height() > size) {
114 114 QString label = text + "...";
115 115 while (boundingRect.height() >= size && label.length() > 3) {
116 116 label.remove(label.length() - 4, 1);
117 117 boundingRect = labelBoundingRect(fn, label);
118 118 }
119 119 labelItem->setText(label);
120 120 } else {
121 121 labelItem->setText(text);
122 122 }
123 123
124 124 //label transformation origin point
125 125 const QRectF& rect = labelItem->boundingRect();
126 126 QPointF center = rect.center();
127 127 labelItem->setTransformOriginPoint(center.x(), center.y());
128 128 int heightDiff = rect.height() - boundingRect.height();
129 129
130 130 //ticks and label position
131 131 if (alignment() == Qt::AlignTop) {
132 132 labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height() + (heightDiff / 2) - labelPadding());
133 133 tickItem->setLine(layout[i], axisRect.bottom(), layout[i], axisRect.bottom() - labelPadding());
134 134 } else if (alignment() == Qt::AlignBottom) {
135 135 labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2) + labelPadding());
136 136 tickItem->setLine(layout[i], axisRect.top(), layout[i], axisRect.top() + labelPadding());
137 137 }
138 138
139 139 //label in beetwen
140 140 if(intervalAxis()&& i+1!=layout.size()) {
141 141 const qreal delta = (layout[i+1] - layout[i])/2;
142 142 labelItem->setPos(layout[i] + delta - center.x(), labelItem->pos().y());
143 143 }
144 144
145 //label overlap detection
145 //label overlap detection - compensate one pixel for rounding errors
146 146 if(labelItem->pos().x() < width ||
147 labelItem->pos().x() < axisRect.left() ||
148 labelItem->pos().x() + boundingRect.width() -1 > axisRect.right()){
147 labelItem->pos().x() < (axisRect.left() - 1.0) ||
148 (labelItem->pos().x() + boundingRect.width() - 1.0) > axisRect.right()){
149 149 labelItem->setVisible(false);
150 150 } else {
151 151 labelItem->setVisible(true);
152 152 width = boundingRect.width() + labelItem->pos().x();
153 153 }
154 154
155 155 //shades
156 156 if ((i + 1) % 2 && i > 1) {
157 157 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
158 158 rectItem->setRect(layout[i - 1], gridRect.top(), layout[i] - layout[i - 1], gridRect.height());
159 159 }
160 160
161 161 // check if the grid line and the axis tick should be shown
162 162 qreal x = gridItem->line().p1().x();
163 163 if (x < gridRect.left() || x > gridRect.right()) {
164 164 gridItem->setVisible(false);
165 165 tickItem->setVisible(false);
166 166 }else{
167 167 gridItem->setVisible(true);
168 168 tickItem->setVisible(true);
169 169 }
170 170
171 171 }
172 172
173 173 //begin/end grid line in case labels between
174 174 if (intervalAxis()) {
175 175 QGraphicsLineItem *gridLine;
176 176 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
177 177 gridLine->setLine(gridRect.right(), gridRect.top(), gridRect.right(), gridRect.bottom());
178 178 gridLine->setVisible(true);
179 179 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
180 180 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.left(), gridRect.bottom());
181 181 gridLine->setVisible(true);
182 182 }
183 183 }
184 184
185 185 QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
186 186 {
187 187 Q_UNUSED(constraint);
188 188 QFontMetrics fn(titleFont());
189 189 QSizeF sh(0,0);
190 190
191 191 if (titleText().isEmpty() || !titleItem()->isVisible())
192 192 return sh;
193 193
194 194 switch (which) {
195 195 case Qt::MinimumSize:
196 196 sh = QSizeF(fn.boundingRect("...").width(), fn.height() + (titlePadding() * 2));
197 197 break;
198 198 case Qt::MaximumSize:
199 199 case Qt::PreferredSize:
200 200 sh = QSizeF(fn.boundingRect(axis()->titleText()).width(), fn.height() + (titlePadding() * 2));
201 201 break;
202 202 default:
203 203 break;
204 204 }
205 205
206 206 return sh;
207 207 }
208 208
209 209 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,221 +1,221
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 Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial 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 "verticalaxis_p.h"
22 22 #include "qabstractaxis.h"
23 23 #include <QFontMetrics>
24 24 #include <QDebug>
25 25
26 26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 27
28 28 VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem* item, bool intervalAxis)
29 29 : ChartAxis(axis, item, intervalAxis)
30 30 {
31 31
32 32 }
33 33
34 34 VerticalAxis::~VerticalAxis()
35 35 {
36 36
37 37 }
38 38
39 39 void VerticalAxis::updateGeometry()
40 40 {
41 41 const QVector<qreal> &layout = ChartAxis::layout();
42 42
43 43 if (layout.isEmpty())
44 44 return;
45 45
46 46 QStringList labelList = labels();
47 47
48 48 QList<QGraphicsItem *> lines = lineItems();
49 49 QList<QGraphicsItem *> labels = labelItems();
50 50 QList<QGraphicsItem *> shades = shadeItems();
51 51 QList<QGraphicsItem *> axis = arrowItems();
52 52 QGraphicsSimpleTextItem* title = titleItem();
53 53
54 54 Q_ASSERT(labels.size() == labelList.size());
55 55 Q_ASSERT(layout.size() == labelList.size());
56 56
57 57 const QRectF &axisRect = axisGeometry();
58 58 const QRectF &gridRect = gridGeometry();
59 59
60 60 qreal height = axisRect.bottom();
61 61
62 62
63 63 //arrow
64 64 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(axis.at(0));
65 65
66 66 //arrow position
67 67 if (alignment()==Qt::AlignLeft)
68 68 arrowItem->setLine( axisRect.right() , gridRect.top(), axisRect.right(), gridRect.bottom());
69 69 else if(alignment()==Qt::AlignRight)
70 70 arrowItem->setLine( axisRect.left() , gridRect.top(), axisRect.left(), gridRect.bottom());
71 71
72 72 QFontMetrics fn(font());
73 73
74 74 //title
75 75 int titlePad = 0;
76 76 QRectF titleBoundingRect;
77 77 if (!titleText().isEmpty() && titleItem()->isVisible()) {
78 78 QFontMetrics fn(title->font());
79 79 int size(0);
80 80 size = gridRect.height();
81 81 QString titleText = this->titleText();
82 82
83 83 if (fn.boundingRect(titleText).width() > size) {
84 84 QString string = titleText + "...";
85 85 while (fn.boundingRect(string).width() > size && string.length() > 3)
86 86 string.remove(string.length() - 4, 1);
87 87 title->setText(string);
88 88 }
89 89 else {
90 90 title->setText(titleText);
91 91 }
92 92
93 93 titlePad = titlePadding();
94 94 titleBoundingRect = title->boundingRect();
95 95
96 96 QPointF center = gridRect.center() - titleBoundingRect.center();
97 97 if (alignment() == Qt::AlignLeft) {
98 98 title->setPos(axisRect.left() - titleBoundingRect.width() / 2 + titleBoundingRect.height() / 2 + titlePad, center.y());
99 99 }
100 100 else if (alignment() == Qt::AlignRight) {
101 101 title->setPos(axisRect.right() - titleBoundingRect.width() / 2 - titleBoundingRect.height() / 2 - titlePad, center.y());
102 102 }
103 103 title->setTransformOriginPoint(titleBoundingRect.center());
104 104 title->setRotation(270);
105 105 }
106 106
107 107 for (int i = 0; i < layout.size(); ++i) {
108 108
109 109 //items
110 110 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i));
111 111 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(axis.at(i + 1));
112 112 QGraphicsSimpleTextItem *labelItem = static_cast<QGraphicsSimpleTextItem *>(labels.at(i));
113 113
114 114 //grid line
115 115 gridItem->setLine(gridRect.left() , layout[i], gridRect.right(), layout[i]);
116 116
117 117 //label text wrapping
118 118 QString text = labelList.at(i);
119 119 QRectF boundingRect = labelBoundingRect(fn, text);
120 120
121 121 qreal size = axisRect.right() - axisRect.left() - labelPadding() - titleBoundingRect.height() - (titlePad * 2);
122 122 if (boundingRect.width() > size) {
123 123 QString label = text + "...";
124 124 while (boundingRect.width() > size && label.length() > 3) {
125 125 label.remove(label.length() - 4, 1);
126 126 boundingRect = labelBoundingRect(fn, label);
127 127 }
128 128 labelItem->setText(label);
129 129 } else {
130 130 labelItem->setText(text);
131 131 }
132 132
133 133 //label transformation origin point
134 134 const QRectF &rect = labelItem->boundingRect();
135 135
136 136 QPointF center = rect.center();
137 137 labelItem->setTransformOriginPoint(center.x(), center.y());
138 138 int widthDiff = rect.width() - boundingRect.width();
139 139
140 140 //ticks and label position
141 141 if (alignment() == Qt::AlignLeft) {
142 142 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2) - labelPadding(), layout[i] - center.y());
143 143 tickItem->setLine(axisRect.right() - labelPadding(), layout[i], axisRect.right(), layout[i]);
144 144 } else if (alignment() == Qt::AlignRight) {
145 145 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2), layout[i] - center.y());
146 146 tickItem->setLine(axisRect.left(), layout[i], axisRect.left() + labelPadding(), layout[i]);
147 147 }
148 148
149 149 //label in beetwen
150 150 if(intervalAxis()&& i+1!=layout.size()) {
151 151 const qreal delta = (layout[i+1] - layout[i])/2;
152 152 labelItem->setPos(labelItem->pos().x() , layout[i] + delta - center.y());
153 153 }
154 154
155 //label overlap detection
156 if(labelItem->pos().y() + boundingRect.height() > height ||
157 labelItem->pos().y() + boundingRect.height()/2 > axisRect.bottom() ||
158 labelItem->pos().y() + boundingRect.height()/2 < axisRect.top()) {
155 //label overlap detection - compensate one pixel for rounding errors
156 if (labelItem->pos().y() + boundingRect.height() > height ||
157 (labelItem->pos().y() + (boundingRect.height() / 2.0) - 1.0) > axisRect.bottom() ||
158 labelItem->pos().y() + (boundingRect.height() / 2.0) < (axisRect.top() - 1.0)) {
159 159 labelItem->setVisible(false);
160 160 }
161 161 else {
162 162 labelItem->setVisible(true);
163 163 height=labelItem->pos().y();
164 164 }
165 165
166 166 //shades
167 167 if ((i + 1) % 2 && i > 1) {
168 168 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
169 169 rectItem->setRect(gridRect.left(), layout[i], gridRect.width(), layout[i - 1] - layout[i]);
170 170 }
171 171
172 172 // check if the grid line and the axis tick should be shown
173 173 qreal y = gridItem->line().p1().y();
174 174 if ((y < gridRect.top() || y > gridRect.bottom()))
175 175 {
176 176 gridItem->setVisible(false);
177 177 tickItem->setVisible(false);
178 178 }else{
179 179 gridItem->setVisible(true);
180 180 tickItem->setVisible(true);
181 181 }
182 182
183 183 }
184 184 //begin/end grid line in case labels between
185 185 if (intervalAxis()) {
186 186 QGraphicsLineItem *gridLine;
187 187 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
188 188 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
189 189 gridLine->setVisible(true);
190 190 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
191 191 gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
192 192 gridLine->setVisible(true);
193 193 }
194 194 }
195 195
196 196 QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
197 197 {
198 198
199 199 Q_UNUSED(constraint);
200 200 QFontMetrics fn(titleFont());
201 201 QSizeF sh(0,0);
202 202
203 203 if (titleText().isEmpty() || !titleItem()->isVisible())
204 204 return sh;
205 205
206 206 switch (which) {
207 207 case Qt::MinimumSize:
208 208 sh = QSizeF(fn.height() + (titlePadding() * 2), fn.boundingRect("...").width());
209 209 break;
210 210 case Qt::MaximumSize:
211 211 case Qt::PreferredSize:
212 212 sh = QSizeF(fn.height() + (titlePadding() * 2), fn.boundingRect(axis()->titleText()).width());
213 213 break;
214 214 default:
215 215 break;
216 216 }
217 217
218 218 return sh;
219 219 }
220 220
221 221 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now