##// END OF EJS Templates
Prevent drawing shades off-chart...
Miikka Heikkinen -
r2448:77b53b7a51e4
parent child
Show More
@@ -1,218 +1,224
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 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 147 && (leftBound == gridRect.left() || rightBound == gridRect.right())) {
148 148 forceHide = true;
149 149 } else {
150 150 labelItem->setPos(leftBound + (delta / 2.0) - center.x(), labelItem->pos().y());
151 151 }
152 152 }
153 153
154 154 //label overlap detection - compensate one pixel for rounding errors
155 155 if (labelItem->pos().x() < width || forceHide ||
156 156 labelItem->pos().x() < (axisRect.left() - 1.0) ||
157 157 (labelItem->pos().x() + boundingRect.width() - 1.0) > axisRect.right()){
158 158 labelItem->setVisible(false);
159 159 } else {
160 160 labelItem->setVisible(true);
161 161 width = boundingRect.width() + labelItem->pos().x();
162 162 }
163 163
164 164 //shades
165 165 if ((i + 1) % 2 && i > 1) {
166 166 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
167 rectItem->setRect(layout[i - 1], gridRect.top(), layout[i] - layout[i - 1], gridRect.height());
167 qreal leftBound = qMax(layout[i - 1], gridRect.left());
168 qreal rightBound = qMin(layout[i], gridRect.right());
169 rectItem->setRect(leftBound, gridRect.top(), rightBound - leftBound, gridRect.height());
170 if (rectItem->rect().width() <= 0.0)
171 rectItem->setVisible(false);
172 else
173 rectItem->setVisible(true);
168 174 }
169 175
170 176 // check if the grid line and the axis tick should be shown
171 177 qreal x = gridItem->line().p1().x();
172 178 if (x < gridRect.left() || x > gridRect.right()) {
173 179 gridItem->setVisible(false);
174 180 tickItem->setVisible(false);
175 181 }else{
176 182 gridItem->setVisible(true);
177 183 tickItem->setVisible(true);
178 184 }
179 185
180 186 }
181 187
182 188 //begin/end grid line in case labels between
183 189 if (intervalAxis()) {
184 190 QGraphicsLineItem *gridLine;
185 191 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
186 192 gridLine->setLine(gridRect.right(), gridRect.top(), gridRect.right(), gridRect.bottom());
187 193 gridLine->setVisible(true);
188 194 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
189 195 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.left(), gridRect.bottom());
190 196 gridLine->setVisible(true);
191 197 }
192 198 }
193 199
194 200 QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
195 201 {
196 202 Q_UNUSED(constraint);
197 203 QFontMetrics fn(titleFont());
198 204 QSizeF sh(0,0);
199 205
200 206 if (titleText().isEmpty() || !titleItem()->isVisible())
201 207 return sh;
202 208
203 209 switch (which) {
204 210 case Qt::MinimumSize:
205 211 sh = QSizeF(fn.boundingRect("...").width(), fn.height() + (titlePadding() * 2));
206 212 break;
207 213 case Qt::MaximumSize:
208 214 case Qt::PreferredSize:
209 215 sh = QSizeF(fn.boundingRect(axis()->titleText()).width(), fn.height() + (titlePadding() * 2));
210 216 break;
211 217 default:
212 218 break;
213 219 }
214 220
215 221 return sh;
216 222 }
217 223
218 224 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,230 +1,236
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 between
150 150 bool forceHide = false;
151 151 if (intervalAxis() && (i + 1) != layout.size()) {
152 152 qreal lowerBound = qMin(layout[i], gridRect.bottom());
153 153 qreal upperBound = qMax(layout[i + 1], gridRect.top());
154 154 const qreal delta = lowerBound - upperBound;
155 155 // Hide label in case visible part of the category at the grid edge is too narrow
156 156 if (delta < boundingRect.height()
157 157 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())) {
158 158 forceHide = true;
159 159 } else {
160 160 labelItem->setPos(labelItem->pos().x() , lowerBound - (delta / 2.0) - center.y());
161 161 }
162 162 }
163 163
164 164 //label overlap detection - compensate one pixel for rounding errors
165 165 if (labelItem->pos().y() + boundingRect.height() > height || forceHide ||
166 166 (labelItem->pos().y() + (boundingRect.height() / 2.0) - 1.0) > axisRect.bottom() ||
167 167 labelItem->pos().y() + (boundingRect.height() / 2.0) < (axisRect.top() - 1.0)) {
168 168 labelItem->setVisible(false);
169 169 }
170 170 else {
171 171 labelItem->setVisible(true);
172 172 height=labelItem->pos().y();
173 173 }
174 174
175 175 //shades
176 176 if ((i + 1) % 2 && i > 1) {
177 177 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
178 rectItem->setRect(gridRect.left(), layout[i], gridRect.width(), layout[i - 1] - layout[i]);
178 qreal lowerBound = qMin(layout[i - 1], gridRect.bottom());
179 qreal upperBound = qMax(layout[i], gridRect.top());
180 rectItem->setRect(gridRect.left(), upperBound, gridRect.width(), lowerBound - upperBound);
181 if (rectItem->rect().height() <= 0.0)
182 rectItem->setVisible(false);
183 else
184 rectItem->setVisible(true);
179 185 }
180 186
181 187 // check if the grid line and the axis tick should be shown
182 188 qreal y = gridItem->line().p1().y();
183 189 if ((y < gridRect.top() || y > gridRect.bottom()))
184 190 {
185 191 gridItem->setVisible(false);
186 192 tickItem->setVisible(false);
187 193 }else{
188 194 gridItem->setVisible(true);
189 195 tickItem->setVisible(true);
190 196 }
191 197
192 198 }
193 199 //begin/end grid line in case labels between
194 200 if (intervalAxis()) {
195 201 QGraphicsLineItem *gridLine;
196 202 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
197 203 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
198 204 gridLine->setVisible(true);
199 205 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
200 206 gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
201 207 gridLine->setVisible(true);
202 208 }
203 209 }
204 210
205 211 QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
206 212 {
207 213
208 214 Q_UNUSED(constraint);
209 215 QFontMetrics fn(titleFont());
210 216 QSizeF sh(0,0);
211 217
212 218 if (titleText().isEmpty() || !titleItem()->isVisible())
213 219 return sh;
214 220
215 221 switch (which) {
216 222 case Qt::MinimumSize:
217 223 sh = QSizeF(fn.height() + (titlePadding() * 2), fn.boundingRect("...").width());
218 224 break;
219 225 case Qt::MaximumSize:
220 226 case Qt::PreferredSize:
221 227 sh = QSizeF(fn.height() + (titlePadding() * 2), fn.boundingRect(axis()->titleText()).width());
222 228 break;
223 229 default:
224 230 break;
225 231 }
226 232
227 233 return sh;
228 234 }
229 235
230 236 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now