##// END OF EJS Templates
Fix multiline axis titles truncation...
Miikka Heikkinen -
r2540:18da5db7d538
parent child
Show More
@@ -1,149 +1,149
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 // W A R N I N G
21 // W A R N I N G
22 // -------------
22 // -------------
23 //
23 //
24 // This file is not part of the QtCommercial Chart API. It exists purely as an
24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 // implementation detail. This header file may change from version to
25 // implementation detail. This header file may change from version to
26 // version without notice, or even be removed.
26 // version without notice, or even be removed.
27 //
27 //
28 // We mean it.
28 // We mean it.
29
29
30 #ifndef CHARTAXISELEMENT_H
30 #ifndef CHARTAXISELEMENT_H
31 #define CHARTAXISELEMENT_H
31 #define CHARTAXISELEMENT_H
32
32
33 #include "qchartglobal.h"
33 #include "qchartglobal.h"
34 #include "chartelement_p.h"
34 #include "chartelement_p.h"
35 #include "axisanimation_p.h"
35 #include "axisanimation_p.h"
36 #include <QGraphicsItem>
36 #include <QGraphicsItem>
37 #include <QGraphicsLayoutItem>
37 #include <QGraphicsLayoutItem>
38 #include <QFont>
38 #include <QFont>
39
39
40 QTCOMMERCIALCHART_BEGIN_NAMESPACE
40 QTCOMMERCIALCHART_BEGIN_NAMESPACE
41
41
42 class ChartPresenter;
42 class ChartPresenter;
43 class QAbstractAxis;
43 class QAbstractAxis;
44
44
45 class ChartAxisElement : public ChartElement, public QGraphicsLayoutItem
45 class ChartAxisElement : public ChartElement, public QGraphicsLayoutItem
46 {
46 {
47 Q_OBJECT
47 Q_OBJECT
48 public:
48 public:
49 ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis = false);
49 ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis = false);
50 ~ChartAxisElement();
50 ~ChartAxisElement();
51
51
52 virtual QRectF gridGeometry() const = 0;
52 virtual QRectF gridGeometry() const = 0;
53 virtual void setGeometry(const QRectF &axis, const QRectF &grid) = 0;
53 virtual void setGeometry(const QRectF &axis, const QRectF &grid) = 0;
54 virtual bool isEmpty() = 0;
54 virtual bool isEmpty() = 0;
55
55
56 void setAnimation(AxisAnimation *animation) { m_animation = animation; }
56 void setAnimation(AxisAnimation *animation) { m_animation = animation; }
57 AxisAnimation *animation() const { return m_animation; }
57 AxisAnimation *animation() const { return m_animation; }
58
58
59 QAbstractAxis *axis() const { return m_axis; }
59 QAbstractAxis *axis() const { return m_axis; }
60 void setLayout(QVector<qreal> &layout) { m_layout = layout; }
60 void setLayout(QVector<qreal> &layout) { m_layout = layout; }
61 QVector<qreal> &layout() { return m_layout; } // Modifiable reference
61 QVector<qreal> &layout() { return m_layout; } // Modifiable reference
62 int labelPadding() const { return 5; }
62 inline qreal labelPadding() const { return qreal(5.0); }
63 int titlePadding() const { return 3; }
63 inline qreal titlePadding() const { return qreal(3.0); }
64 void setLabels(const QStringList &labels) { m_labelsList = labels; }
64 void setLabels(const QStringList &labels) { m_labelsList = labels; }
65 QStringList labels() const { return m_labelsList; }
65 QStringList labels() const { return m_labelsList; }
66
66
67 qreal min() const;
67 qreal min() const;
68 qreal max() const;
68 qreal max() const;
69
69
70 QRectF axisGeometry() const { return m_axisRect; }
70 QRectF axisGeometry() const { return m_axisRect; }
71 void setAxisGeometry(const QRectF &axisGeometry) { m_axisRect = axisGeometry; }
71 void setAxisGeometry(const QRectF &axisGeometry) { m_axisRect = axisGeometry; }
72
72
73 void axisSelected();
73 void axisSelected();
74
74
75 //this flag indicates that axis is used to show intervals it means labels are in between ticks
75 //this flag indicates that axis is used to show intervals it means labels are in between ticks
76 bool intervalAxis() const { return m_intervalAxis; }
76 bool intervalAxis() const { return m_intervalAxis; }
77
77
78 static QStringList createValueLabels(qreal max, qreal min, int ticks, const QString &format);
78 static QStringList createValueLabels(qreal max, qreal min, int ticks, const QString &format);
79 static QStringList createLogValueLabels(qreal min, qreal max, qreal base, int ticks, const QString &format);
79 static QStringList createLogValueLabels(qreal min, qreal max, qreal base, int ticks, const QString &format);
80 static QStringList createDateTimeLabels(qreal max, qreal min, int ticks, const QString &format);
80 static QStringList createDateTimeLabels(qreal max, qreal min, int ticks, const QString &format);
81
81
82 // from QGraphicsLayoutItem
82 // from QGraphicsLayoutItem
83 QRectF boundingRect() const
83 QRectF boundingRect() const
84 {
84 {
85 return QRectF();
85 return QRectF();
86 }
86 }
87
87
88 // from QGraphicsLayoutItem
88 // from QGraphicsLayoutItem
89 void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
89 void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
90 {
90 {
91 }
91 }
92
92
93 protected:
93 protected:
94 virtual QVector<qreal> calculateLayout() const = 0;
94 virtual QVector<qreal> calculateLayout() const = 0;
95 virtual void updateLayout(QVector<qreal> &layout) = 0;
95 virtual void updateLayout(QVector<qreal> &layout) = 0;
96
96
97 QList<QGraphicsItem *> gridItems() { return m_grid->childItems(); }
97 QList<QGraphicsItem *> gridItems() { return m_grid->childItems(); }
98 QList<QGraphicsItem *> labelItems() { return m_labels->childItems(); }
98 QList<QGraphicsItem *> labelItems() { return m_labels->childItems(); }
99 QList<QGraphicsItem *> shadeItems() { return m_shades->childItems(); }
99 QList<QGraphicsItem *> shadeItems() { return m_shades->childItems(); }
100 QList<QGraphicsItem *> arrowItems() { return m_arrow->childItems(); }
100 QList<QGraphicsItem *> arrowItems() { return m_arrow->childItems(); }
101 QGraphicsTextItem *titleItem() const { return m_title.data(); }
101 QGraphicsTextItem *titleItem() const { return m_title.data(); }
102 QGraphicsItemGroup *gridGroup() { return m_grid.data(); }
102 QGraphicsItemGroup *gridGroup() { return m_grid.data(); }
103 QGraphicsItemGroup *labelGroup() { return m_labels.data(); }
103 QGraphicsItemGroup *labelGroup() { return m_labels.data(); }
104 QGraphicsItemGroup *shadeGroup() { return m_shades.data(); }
104 QGraphicsItemGroup *shadeGroup() { return m_shades.data(); }
105 QGraphicsItemGroup *arrowGroup() { return m_arrow.data(); }
105 QGraphicsItemGroup *arrowGroup() { return m_arrow.data(); }
106
106
107 public Q_SLOTS:
107 public Q_SLOTS:
108 void handleVisibleChanged(bool visible);
108 void handleVisibleChanged(bool visible);
109 void handleArrowVisibleChanged(bool visible);
109 void handleArrowVisibleChanged(bool visible);
110 void handleGridVisibleChanged(bool visible);
110 void handleGridVisibleChanged(bool visible);
111 void handleLabelsVisibleChanged(bool visible);
111 void handleLabelsVisibleChanged(bool visible);
112 void handleShadesVisibleChanged(bool visible);
112 void handleShadesVisibleChanged(bool visible);
113 void handleLabelsAngleChanged(int angle);
113 void handleLabelsAngleChanged(int angle);
114 virtual void handleShadesBrushChanged(const QBrush &brush) = 0;
114 virtual void handleShadesBrushChanged(const QBrush &brush) = 0;
115 virtual void handleShadesPenChanged(const QPen &pen) = 0;
115 virtual void handleShadesPenChanged(const QPen &pen) = 0;
116 virtual void handleArrowPenChanged(const QPen &pen) = 0;
116 virtual void handleArrowPenChanged(const QPen &pen) = 0;
117 virtual void handleGridPenChanged(const QPen &pen) = 0;
117 virtual void handleGridPenChanged(const QPen &pen) = 0;
118 void handleLabelsPenChanged(const QPen &pen);
118 void handleLabelsPenChanged(const QPen &pen);
119 void handleLabelsBrushChanged(const QBrush &brush);
119 void handleLabelsBrushChanged(const QBrush &brush);
120 void handleLabelsFontChanged(const QFont &font);
120 void handleLabelsFontChanged(const QFont &font);
121 void handleTitlePenChanged(const QPen &pen);
121 void handleTitlePenChanged(const QPen &pen);
122 void handleTitleBrushChanged(const QBrush &brush);
122 void handleTitleBrushChanged(const QBrush &brush);
123 void handleTitleFontChanged(const QFont &font);
123 void handleTitleFontChanged(const QFont &font);
124 void handleTitleTextChanged(const QString &title);
124 void handleTitleTextChanged(const QString &title);
125 void handleTitleVisibleChanged(bool visible);
125 void handleTitleVisibleChanged(bool visible);
126 void handleRangeChanged(qreal min, qreal max);
126 void handleRangeChanged(qreal min, qreal max);
127
127
128 Q_SIGNALS:
128 Q_SIGNALS:
129 void clicked();
129 void clicked();
130
130
131 private:
131 private:
132 void connectSlots();
132 void connectSlots();
133
133
134 QAbstractAxis *m_axis;
134 QAbstractAxis *m_axis;
135 AxisAnimation *m_animation;
135 AxisAnimation *m_animation;
136 QVector<qreal> m_layout;
136 QVector<qreal> m_layout;
137 QStringList m_labelsList;
137 QStringList m_labelsList;
138 QRectF m_axisRect;
138 QRectF m_axisRect;
139 QScopedPointer<QGraphicsItemGroup> m_grid;
139 QScopedPointer<QGraphicsItemGroup> m_grid;
140 QScopedPointer<QGraphicsItemGroup> m_arrow;
140 QScopedPointer<QGraphicsItemGroup> m_arrow;
141 QScopedPointer<QGraphicsItemGroup> m_shades;
141 QScopedPointer<QGraphicsItemGroup> m_shades;
142 QScopedPointer<QGraphicsItemGroup> m_labels;
142 QScopedPointer<QGraphicsItemGroup> m_labels;
143 QScopedPointer<QGraphicsTextItem> m_title;
143 QScopedPointer<QGraphicsTextItem> m_title;
144 bool m_intervalAxis;
144 bool m_intervalAxis;
145 };
145 };
146
146
147 QTCOMMERCIALCHART_END_NAMESPACE
147 QTCOMMERCIALCHART_END_NAMESPACE
148
148
149 #endif /* CHARTAXISELEMENT_H */
149 #endif /* CHARTAXISELEMENT_H */
@@ -1,206 +1,223
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "horizontalaxis_p.h"
21 #include "horizontalaxis_p.h"
22 #include "qabstractaxis_p.h"
22 #include "qabstractaxis_p.h"
23 #include "chartpresenter_p.h"
23 #include "chartpresenter_p.h"
24 #include <qmath.h>
24 #include <qmath.h>
25 #include <QDebug>
25 #include <QDebug>
26
26
27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28
28
29 HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
29 HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
30 : CartesianChartAxis(axis, item, intervalAxis)
30 : CartesianChartAxis(axis, item, intervalAxis)
31 {
31 {
32 }
32 }
33
33
34 HorizontalAxis::~HorizontalAxis()
34 HorizontalAxis::~HorizontalAxis()
35 {
35 {
36 }
36 }
37
37
38 void HorizontalAxis::updateGeometry()
38 void HorizontalAxis::updateGeometry()
39 {
39 {
40 const QVector<qreal> &layout = ChartAxisElement::layout();
40 const QVector<qreal> &layout = ChartAxisElement::layout();
41
41
42 if (layout.isEmpty())
42 if (layout.isEmpty())
43 return;
43 return;
44
44
45 QStringList labelList = labels();
45 QStringList labelList = labels();
46
46
47 QList<QGraphicsItem *> lines = gridItems();
47 QList<QGraphicsItem *> lines = gridItems();
48 QList<QGraphicsItem *> labels = labelItems();
48 QList<QGraphicsItem *> labels = labelItems();
49 QList<QGraphicsItem *> shades = shadeItems();
49 QList<QGraphicsItem *> shades = shadeItems();
50 QList<QGraphicsItem *> arrow = arrowItems();
50 QList<QGraphicsItem *> arrow = arrowItems();
51 QGraphicsTextItem *title = titleItem();
51 QGraphicsTextItem *title = titleItem();
52
52
53 Q_ASSERT(labels.size() == labelList.size());
53 Q_ASSERT(labels.size() == labelList.size());
54 Q_ASSERT(layout.size() == labelList.size());
54 Q_ASSERT(layout.size() == labelList.size());
55
55
56 const QRectF &axisRect = axisGeometry();
56 const QRectF &axisRect = axisGeometry();
57 const QRectF &gridRect = gridGeometry();
57 const QRectF &gridRect = gridGeometry();
58
58
59 //arrow
59 //arrow
60 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(arrow.at(0));
60 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(arrow.at(0));
61
61
62 if (axis()->alignment() == Qt::AlignTop)
62 if (axis()->alignment() == Qt::AlignTop)
63 arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom());
63 arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom());
64 else if (axis()->alignment() == Qt::AlignBottom)
64 else if (axis()->alignment() == Qt::AlignBottom)
65 arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
65 arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
66
66
67 qreal width = 0;
67 qreal width = 0;
68
68
69 //title
69 //title
70 int titlePad = 0;
71 QRectF titleBoundingRect;
70 QRectF titleBoundingRect;
72 QString titleText = axis()->titleText();
71 QString titleText = axis()->titleText();
72 qreal availableSpace = axisRect.height() - labelPadding();
73 if (!titleText.isEmpty() && titleItem()->isVisible()) {
73 if (!titleText.isEmpty() && titleItem()->isVisible()) {
74 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), gridRect.width(), Qt::Horizontal, QRectF()));
74 availableSpace -= titlePadding() * 2.0;
75 qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(), "...").height();
76 QString truncatedTitle = ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
77 gridRect.width(), Qt::Horizontal, titleBoundingRect);
78 qreal titleSpace = availableSpace - minimumLabelHeight;
79 if (titleSpace < titleBoundingRect.height()) {
80 // Need to also truncate title vertically (multiline title)
81 bool skip = false;
82 if (truncatedTitle.endsWith("...")) {
83 if (truncatedTitle.size() == 3)
84 skip = true; // Already truncated to minimum
85 else
86 truncatedTitle.chop(3);
87 }
88 if (!skip)
89 truncatedTitle = ChartPresenter::truncatedText(axis()->titleFont(), truncatedTitle, qreal(0.0),
90 titleSpace, Qt::Vertical, titleBoundingRect);
91 }
92 title->setHtml(truncatedTitle);
75
93
76 titlePad = titlePadding();
77 titleBoundingRect = title->boundingRect();
94 titleBoundingRect = title->boundingRect();
78
95
79 QPointF center = gridRect.center() - titleBoundingRect.center();
96 QPointF center = gridRect.center() - titleBoundingRect.center();
80 if (axis()->alignment() == Qt::AlignTop) {
97 if (axis()->alignment() == Qt::AlignTop)
81 title->setPos(center.x(), axisRect.top() + titlePad);
98 title->setPos(center.x(), axisRect.top() + titlePadding());
82 } else if (axis()->alignment() == Qt::AlignBottom) {
99 else if (axis()->alignment() == Qt::AlignBottom)
83 title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePad);
100 title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePadding());
84 }
101
102 availableSpace -= titleBoundingRect.height();
85 }
103 }
86
104
87 for (int i = 0; i < layout.size(); ++i) {
105 for (int i = 0; i < layout.size(); ++i) {
88 //items
106 //items
89 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem*>(lines.at(i));
107 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem*>(lines.at(i));
90 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(arrow.at(i + 1));
108 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(arrow.at(i + 1));
91 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
109 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
92
110
93 //grid line
111 //grid line
94 gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom());
112 gridItem->setLine(layout[i], gridRect.top(), layout[i], gridRect.bottom());
95
113
96 //label text wrapping
114 //label text wrapping
97 QString text = labelList.at(i);
115 QString text = labelList.at(i);
98 QRectF boundingRect;
116 QRectF boundingRect;
99 qreal size = axisRect.bottom() - axisRect.top() - labelPadding() - titleBoundingRect.height() - (titlePad * 2);
100 labelItem->setHtml(ChartPresenter::truncatedText(axis()->labelsFont(), text, axis()->labelsAngle(),
117 labelItem->setHtml(ChartPresenter::truncatedText(axis()->labelsFont(), text, axis()->labelsAngle(),
101 size, Qt::Vertical, boundingRect));
118 availableSpace, Qt::Vertical, boundingRect));
102
119
103 //label transformation origin point
120 //label transformation origin point
104 const QRectF& rect = labelItem->boundingRect();
121 const QRectF& rect = labelItem->boundingRect();
105 QPointF center = rect.center();
122 QPointF center = rect.center();
106 labelItem->setTransformOriginPoint(center.x(), center.y());
123 labelItem->setTransformOriginPoint(center.x(), center.y());
107 int heightDiff = rect.height() - boundingRect.height();
124 qreal heightDiff = rect.height() - boundingRect.height();
108
125
109 //ticks and label position
126 //ticks and label position
110 if (axis()->alignment() == Qt::AlignTop) {
127 if (axis()->alignment() == Qt::AlignTop) {
111 labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height() + (heightDiff / 2) - labelPadding());
128 labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height() + (heightDiff / 2.0) - labelPadding());
112 tickItem->setLine(layout[i], axisRect.bottom(), layout[i], axisRect.bottom() - labelPadding());
129 tickItem->setLine(layout[i], axisRect.bottom(), layout[i], axisRect.bottom() - labelPadding());
113 } else if (axis()->alignment() == Qt::AlignBottom) {
130 } else if (axis()->alignment() == Qt::AlignBottom) {
114 labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2) + labelPadding());
131 labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2.0) + labelPadding());
115 tickItem->setLine(layout[i], axisRect.top(), layout[i], axisRect.top() + labelPadding());
132 tickItem->setLine(layout[i], axisRect.top(), layout[i], axisRect.top() + labelPadding());
116 }
133 }
117
134
118 //label in between
135 //label in between
119 bool forceHide = false;
136 bool forceHide = false;
120 if (intervalAxis() && (i + 1) != layout.size()) {
137 if (intervalAxis() && (i + 1) != layout.size()) {
121 qreal leftBound = qMax(layout[i], gridRect.left());
138 qreal leftBound = qMax(layout[i], gridRect.left());
122 qreal rightBound = qMin(layout[i + 1], gridRect.right());
139 qreal rightBound = qMin(layout[i + 1], gridRect.right());
123 const qreal delta = rightBound - leftBound;
140 const qreal delta = rightBound - leftBound;
124 // Hide label in case visible part of the category at the grid edge is too narrow
141 // Hide label in case visible part of the category at the grid edge is too narrow
125 if (delta < boundingRect.width()
142 if (delta < boundingRect.width()
126 && (leftBound == gridRect.left() || rightBound == gridRect.right())) {
143 && (leftBound == gridRect.left() || rightBound == gridRect.right())) {
127 forceHide = true;
144 forceHide = true;
128 } else {
145 } else {
129 labelItem->setPos(leftBound + (delta / 2.0) - center.x(), labelItem->pos().y());
146 labelItem->setPos(leftBound + (delta / 2.0) - center.x(), labelItem->pos().y());
130 }
147 }
131 }
148 }
132
149
133 //label overlap detection - compensate one pixel for rounding errors
150 //label overlap detection - compensate one pixel for rounding errors
134 if (labelItem->pos().x() < width || forceHide ||
151 if (labelItem->pos().x() < width || forceHide ||
135 labelItem->pos().x() < (axisRect.left() - 1.0) ||
152 labelItem->pos().x() < (axisRect.left() - 1.0) ||
136 (labelItem->pos().x() + boundingRect.width() - 1.0) > axisRect.right()){
153 (labelItem->pos().x() + boundingRect.width() - 1.0) > axisRect.right()){
137 labelItem->setVisible(false);
154 labelItem->setVisible(false);
138 } else {
155 } else {
139 labelItem->setVisible(true);
156 labelItem->setVisible(true);
140 width = boundingRect.width() + labelItem->pos().x();
157 width = boundingRect.width() + labelItem->pos().x();
141 }
158 }
142
159
143 //shades
160 //shades
144 if ((i + 1) % 2 && i > 1) {
161 if ((i + 1) % 2 && i > 1) {
145 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
162 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
146 qreal leftBound = qMax(layout[i - 1], gridRect.left());
163 qreal leftBound = qMax(layout[i - 1], gridRect.left());
147 qreal rightBound = qMin(layout[i], gridRect.right());
164 qreal rightBound = qMin(layout[i], gridRect.right());
148 rectItem->setRect(leftBound, gridRect.top(), rightBound - leftBound, gridRect.height());
165 rectItem->setRect(leftBound, gridRect.top(), rightBound - leftBound, gridRect.height());
149 if (rectItem->rect().width() <= 0.0)
166 if (rectItem->rect().width() <= 0.0)
150 rectItem->setVisible(false);
167 rectItem->setVisible(false);
151 else
168 else
152 rectItem->setVisible(true);
169 rectItem->setVisible(true);
153 }
170 }
154
171
155 // check if the grid line and the axis tick should be shown
172 // check if the grid line and the axis tick should be shown
156 qreal x = gridItem->line().p1().x();
173 qreal x = gridItem->line().p1().x();
157 if (x < gridRect.left() || x > gridRect.right()) {
174 if (x < gridRect.left() || x > gridRect.right()) {
158 gridItem->setVisible(false);
175 gridItem->setVisible(false);
159 tickItem->setVisible(false);
176 tickItem->setVisible(false);
160 } else {
177 } else {
161 gridItem->setVisible(true);
178 gridItem->setVisible(true);
162 tickItem->setVisible(true);
179 tickItem->setVisible(true);
163 }
180 }
164
181
165 }
182 }
166
183
167 //begin/end grid line in case labels between
184 //begin/end grid line in case labels between
168 if (intervalAxis()) {
185 if (intervalAxis()) {
169 QGraphicsLineItem *gridLine;
186 QGraphicsLineItem *gridLine;
170 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
187 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
171 gridLine->setLine(gridRect.right(), gridRect.top(), gridRect.right(), gridRect.bottom());
188 gridLine->setLine(gridRect.right(), gridRect.top(), gridRect.right(), gridRect.bottom());
172 gridLine->setVisible(true);
189 gridLine->setVisible(true);
173 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
190 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
174 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.left(), gridRect.bottom());
191 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.left(), gridRect.bottom());
175 gridLine->setVisible(true);
192 gridLine->setVisible(true);
176 }
193 }
177 }
194 }
178
195
179 QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
196 QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
180 {
197 {
181 Q_UNUSED(constraint);
198 Q_UNUSED(constraint);
182 QSizeF sh(0,0);
199 QSizeF sh(0,0);
183
200
184 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
201 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
185 return sh;
202 return sh;
186
203
187 switch (which) {
204 switch (which) {
188 case Qt::MinimumSize: {
205 case Qt::MinimumSize: {
189 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), "...");
206 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), "...");
190 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2));
207 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
191 break;
208 break;
192 }
209 }
193 case Qt::MaximumSize:
210 case Qt::MaximumSize:
194 case Qt::PreferredSize: {
211 case Qt::PreferredSize: {
195 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
212 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
196 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2));
213 sh = QSizeF(titleRect.width(), titleRect.height() + (titlePadding() * 2.0));
197 break;
214 break;
198 }
215 }
199 default:
216 default:
200 break;
217 break;
201 }
218 }
202
219
203 return sh;
220 return sh;
204 }
221 }
205
222
206 QTCOMMERCIALCHART_END_NAMESPACE
223 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,408 +1,408
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "polarchartaxisangular_p.h"
21 #include "polarchartaxisangular_p.h"
22 #include "chartpresenter_p.h"
22 #include "chartpresenter_p.h"
23 #include "abstractchartlayout_p.h"
23 #include "abstractchartlayout_p.h"
24 #include "qabstractaxis.h"
24 #include "qabstractaxis.h"
25 #include "qabstractaxis_p.h"
25 #include "qabstractaxis_p.h"
26 #include <QDebug>
26 #include <QDebug>
27
27
28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
29
29
30 PolarChartAxisAngular::PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
30 PolarChartAxisAngular::PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
31 : PolarChartAxis(axis, item, intervalAxis)
31 : PolarChartAxis(axis, item, intervalAxis)
32 {
32 {
33 }
33 }
34
34
35 PolarChartAxisAngular::~PolarChartAxisAngular()
35 PolarChartAxisAngular::~PolarChartAxisAngular()
36 {
36 {
37 }
37 }
38
38
39 void PolarChartAxisAngular::updateGeometry()
39 void PolarChartAxisAngular::updateGeometry()
40 {
40 {
41 QGraphicsLayoutItem::updateGeometry();
41 QGraphicsLayoutItem::updateGeometry();
42
42
43 const QVector<qreal> &layout = this->layout();
43 const QVector<qreal> &layout = this->layout();
44 if (layout.isEmpty())
44 if (layout.isEmpty())
45 return;
45 return;
46
46
47 createAxisLabels(layout);
47 createAxisLabels(layout);
48 QStringList labelList = labels();
48 QStringList labelList = labels();
49 QPointF center = axisGeometry().center();
49 QPointF center = axisGeometry().center();
50 QList<QGraphicsItem *> arrowItemList = arrowItems();
50 QList<QGraphicsItem *> arrowItemList = arrowItems();
51 QList<QGraphicsItem *> gridItemList = gridItems();
51 QList<QGraphicsItem *> gridItemList = gridItems();
52 QList<QGraphicsItem *> labelItemList = labelItems();
52 QList<QGraphicsItem *> labelItemList = labelItems();
53 QList<QGraphicsItem *> shadeItemList = shadeItems();
53 QList<QGraphicsItem *> shadeItemList = shadeItems();
54 QGraphicsTextItem *title = titleItem();
54 QGraphicsTextItem *title = titleItem();
55
55
56 QGraphicsEllipseItem *axisLine = static_cast<QGraphicsEllipseItem *>(arrowItemList.at(0));
56 QGraphicsEllipseItem *axisLine = static_cast<QGraphicsEllipseItem *>(arrowItemList.at(0));
57 axisLine->setRect(axisGeometry());
57 axisLine->setRect(axisGeometry());
58
58
59 qreal radius = axisGeometry().height() / 2.0;
59 qreal radius = axisGeometry().height() / 2.0;
60
60
61 QRectF previousLabelRect;
61 QRectF previousLabelRect;
62 QRectF firstLabelRect;
62 QRectF firstLabelRect;
63
63
64 qreal labelHeight = 0;
64 qreal labelHeight = 0;
65
65
66 bool firstShade = true;
66 bool firstShade = true;
67 bool nextTickVisible = false;
67 bool nextTickVisible = false;
68 if (layout.size())
68 if (layout.size())
69 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > 360.0);
69 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > 360.0);
70
70
71 for (int i = 0; i < layout.size(); ++i) {
71 for (int i = 0; i < layout.size(); ++i) {
72 qreal angularCoordinate = layout.at(i);
72 qreal angularCoordinate = layout.at(i);
73
73
74 QGraphicsLineItem *gridLineItem = static_cast<QGraphicsLineItem *>(gridItemList.at(i));
74 QGraphicsLineItem *gridLineItem = static_cast<QGraphicsLineItem *>(gridItemList.at(i));
75 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
75 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
76 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
76 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
77 QGraphicsPathItem *shadeItem = 0;
77 QGraphicsPathItem *shadeItem = 0;
78 if (i == 0)
78 if (i == 0)
79 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
79 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
80 else if (i % 2)
80 else if (i % 2)
81 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
81 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
82
82
83 // Ignore ticks outside valid range
83 // Ignore ticks outside valid range
84 bool currentTickVisible = nextTickVisible;
84 bool currentTickVisible = nextTickVisible;
85 if ((i == layout.size() - 1)
85 if ((i == layout.size() - 1)
86 || layout.at(i + 1) < 0.0
86 || layout.at(i + 1) < 0.0
87 || layout.at(i + 1) > 360.0) {
87 || layout.at(i + 1) > 360.0) {
88 nextTickVisible = false;
88 nextTickVisible = false;
89 } else {
89 } else {
90 nextTickVisible = true;
90 nextTickVisible = true;
91 }
91 }
92
92
93 qreal labelCoordinate = angularCoordinate;
93 qreal labelCoordinate = angularCoordinate;
94 qreal labelVisible = currentTickVisible;
94 qreal labelVisible = currentTickVisible;
95 if (intervalAxis()) {
95 if (intervalAxis()) {
96 qreal farEdge;
96 qreal farEdge;
97 if (i == (layout.size() - 1))
97 if (i == (layout.size() - 1))
98 farEdge = 360.0;
98 farEdge = 360.0;
99 else
99 else
100 farEdge = qMin(qreal(360.0), layout.at(i + 1));
100 farEdge = qMin(qreal(360.0), layout.at(i + 1));
101
101
102 // Adjust the labelCoordinate to show it if next tick is visible
102 // Adjust the labelCoordinate to show it if next tick is visible
103 if (nextTickVisible)
103 if (nextTickVisible)
104 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
104 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
105
105
106 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
106 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
107 // Don't display label once the category gets too small near the axis
107 // Don't display label once the category gets too small near the axis
108 if (labelCoordinate < 5.0 || labelCoordinate > 355.0)
108 if (labelCoordinate < 5.0 || labelCoordinate > 355.0)
109 labelVisible = false;
109 labelVisible = false;
110 else
110 else
111 labelVisible = true;
111 labelVisible = true;
112 }
112 }
113
113
114 // Need this also in label calculations, so determine it first
114 // Need this also in label calculations, so determine it first
115 QLineF tickLine(QLineF::fromPolar(radius - tickWidth(), 90.0 - angularCoordinate).p2(),
115 QLineF tickLine(QLineF::fromPolar(radius - tickWidth(), 90.0 - angularCoordinate).p2(),
116 QLineF::fromPolar(radius + tickWidth(), 90.0 - angularCoordinate).p2());
116 QLineF::fromPolar(radius + tickWidth(), 90.0 - angularCoordinate).p2());
117 tickLine.translate(center);
117 tickLine.translate(center);
118
118
119 // Angular axis label
119 // Angular axis label
120 if (axis()->labelsVisible() && labelVisible) {
120 if (axis()->labelsVisible() && labelVisible) {
121 labelItem->setHtml(labelList.at(i));
121 labelItem->setHtml(labelList.at(i));
122 const QRectF &rect = labelItem->boundingRect();
122 const QRectF &rect = labelItem->boundingRect();
123 QPointF labelCenter = rect.center();
123 QPointF labelCenter = rect.center();
124 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
124 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
125 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
125 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
126 boundingRect.moveCenter(labelCenter);
126 boundingRect.moveCenter(labelCenter);
127 QPointF positionDiff(rect.topLeft() - boundingRect.topLeft());
127 QPointF positionDiff(rect.topLeft() - boundingRect.topLeft());
128
128
129 QPointF labelPoint;
129 QPointF labelPoint;
130 if (intervalAxis()) {
130 if (intervalAxis()) {
131 QLineF labelLine = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate);
131 QLineF labelLine = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate);
132 labelLine.translate(center);
132 labelLine.translate(center);
133 labelPoint = labelLine.p2();
133 labelPoint = labelLine.p2();
134 } else {
134 } else {
135 labelPoint = tickLine.p2();
135 labelPoint = tickLine.p2();
136 }
136 }
137
137
138 QRectF labelRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
138 QRectF labelRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
139 labelItem->setPos(labelRect.topLeft() + positionDiff);
139 labelItem->setPos(labelRect.topLeft() + positionDiff);
140
140
141 // Store height for title calculations
141 // Store height for title calculations
142 qreal labelClearance = axisGeometry().top() - labelRect.top();
142 qreal labelClearance = axisGeometry().top() - labelRect.top();
143 labelHeight = qMax(labelHeight, labelClearance);
143 labelHeight = qMax(labelHeight, labelClearance);
144
144
145 // Label overlap detection
145 // Label overlap detection
146 if (i && (previousLabelRect.intersects(labelRect) || firstLabelRect.intersects(labelRect))) {
146 if (i && (previousLabelRect.intersects(labelRect) || firstLabelRect.intersects(labelRect))) {
147 labelVisible = false;
147 labelVisible = false;
148 } else {
148 } else {
149 // Store labelRect for future comparison. Some area is deducted to make things look
149 // Store labelRect for future comparison. Some area is deducted to make things look
150 // little nicer, as usually intersection happens at label corner with angular labels.
150 // little nicer, as usually intersection happens at label corner with angular labels.
151 labelRect.adjust(-2.0, -4.0, -2.0, -4.0);
151 labelRect.adjust(-2.0, -4.0, -2.0, -4.0);
152 if (firstLabelRect.isEmpty())
152 if (firstLabelRect.isEmpty())
153 firstLabelRect = labelRect;
153 firstLabelRect = labelRect;
154
154
155 previousLabelRect = labelRect;
155 previousLabelRect = labelRect;
156 labelVisible = true;
156 labelVisible = true;
157 }
157 }
158 }
158 }
159
159
160 labelItem->setVisible(labelVisible);
160 labelItem->setVisible(labelVisible);
161 if (!currentTickVisible) {
161 if (!currentTickVisible) {
162 gridLineItem->setVisible(false);
162 gridLineItem->setVisible(false);
163 tickItem->setVisible(false);
163 tickItem->setVisible(false);
164 if (shadeItem)
164 if (shadeItem)
165 shadeItem->setVisible(false);
165 shadeItem->setVisible(false);
166 continue;
166 continue;
167 }
167 }
168
168
169 // Angular grid line
169 // Angular grid line
170 QLineF gridLine = QLineF::fromPolar(radius, 90.0 - angularCoordinate);
170 QLineF gridLine = QLineF::fromPolar(radius, 90.0 - angularCoordinate);
171 gridLine.translate(center);
171 gridLine.translate(center);
172 gridLineItem->setLine(gridLine);
172 gridLineItem->setLine(gridLine);
173 gridLineItem->setVisible(true);
173 gridLineItem->setVisible(true);
174
174
175 // Tick
175 // Tick
176 tickItem->setLine(tickLine);
176 tickItem->setLine(tickLine);
177 tickItem->setVisible(true);
177 tickItem->setVisible(true);
178
178
179 // Shades
179 // Shades
180 if (i % 2 || (i == 0 && !nextTickVisible)) {
180 if (i % 2 || (i == 0 && !nextTickVisible)) {
181 QPainterPath path;
181 QPainterPath path;
182 path.moveTo(center);
182 path.moveTo(center);
183 if (i == 0) {
183 if (i == 0) {
184 // If first tick is also the last, we need to custom fill the first partial arc
184 // If first tick is also the last, we need to custom fill the first partial arc
185 // or it won't get filled.
185 // or it won't get filled.
186 path.arcTo(axisGeometry(), 90.0 - layout.at(0), layout.at(0));
186 path.arcTo(axisGeometry(), 90.0 - layout.at(0), layout.at(0));
187 path.closeSubpath();
187 path.closeSubpath();
188 } else {
188 } else {
189 qreal nextCoordinate;
189 qreal nextCoordinate;
190 if (!nextTickVisible) // Last visible tick
190 if (!nextTickVisible) // Last visible tick
191 nextCoordinate = 360.0;
191 nextCoordinate = 360.0;
192 else
192 else
193 nextCoordinate = layout.at(i + 1);
193 nextCoordinate = layout.at(i + 1);
194 qreal arcSpan = angularCoordinate - nextCoordinate;
194 qreal arcSpan = angularCoordinate - nextCoordinate;
195 path.arcTo(axisGeometry(), 90.0 - angularCoordinate, arcSpan);
195 path.arcTo(axisGeometry(), 90.0 - angularCoordinate, arcSpan);
196 path.closeSubpath();
196 path.closeSubpath();
197
197
198 // Add additional arc for first shade item if there is a partial arc to be filled
198 // Add additional arc for first shade item if there is a partial arc to be filled
199 if (firstShade) {
199 if (firstShade) {
200 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
200 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
201 if (layout.at(i - 1) > 0.0) {
201 if (layout.at(i - 1) > 0.0) {
202 QPainterPath specialPath;
202 QPainterPath specialPath;
203 specialPath.moveTo(center);
203 specialPath.moveTo(center);
204 specialPath.arcTo(axisGeometry(), 90.0 - layout.at(i - 1), layout.at(i - 1));
204 specialPath.arcTo(axisGeometry(), 90.0 - layout.at(i - 1), layout.at(i - 1));
205 specialPath.closeSubpath();
205 specialPath.closeSubpath();
206 specialShadeItem->setPath(specialPath);
206 specialShadeItem->setPath(specialPath);
207 specialShadeItem->setVisible(true);
207 specialShadeItem->setVisible(true);
208 } else {
208 } else {
209 specialShadeItem->setVisible(false);
209 specialShadeItem->setVisible(false);
210 }
210 }
211 }
211 }
212 }
212 }
213 shadeItem->setPath(path);
213 shadeItem->setPath(path);
214 shadeItem->setVisible(true);
214 shadeItem->setVisible(true);
215 firstShade = false;
215 firstShade = false;
216 }
216 }
217 }
217 }
218
218
219 // Title, centered above the chart
219 // Title, centered above the chart
220 QString titleText = axis()->titleText();
220 QString titleText = axis()->titleText();
221 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
221 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
222 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), axisGeometry().width(), Qt::Horizontal, QRectF()));
222 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), axisGeometry().width(), Qt::Horizontal, QRectF()));
223
223
224 QRectF titleBoundingRect = title->boundingRect();
224 QRectF titleBoundingRect = title->boundingRect();
225 QPointF titleCenter = center - titleBoundingRect.center();
225 QPointF titleCenter = center - titleBoundingRect.center();
226 title->setPos(titleCenter.x(), axisGeometry().top() - qreal(titlePadding()) * 2.0 - titleBoundingRect.height() - labelHeight);
226 title->setPos(titleCenter.x(), axisGeometry().top() - titlePadding() * 2.0 - titleBoundingRect.height() - labelHeight);
227 }
227 }
228 }
228 }
229
229
230 Qt::Orientation PolarChartAxisAngular::orientation() const
230 Qt::Orientation PolarChartAxisAngular::orientation() const
231 {
231 {
232 return Qt::Horizontal;
232 return Qt::Horizontal;
233 }
233 }
234
234
235 void PolarChartAxisAngular::createItems(int count)
235 void PolarChartAxisAngular::createItems(int count)
236 {
236 {
237 if (arrowItems().count() == 0) {
237 if (arrowItems().count() == 0) {
238 // angular axis line
238 // angular axis line
239 // TODO: need class similar to LineArrowItem for click handling?
239 // TODO: need class similar to LineArrowItem for click handling?
240 QGraphicsEllipseItem *arrow = new QGraphicsEllipseItem(presenter()->rootItem());
240 QGraphicsEllipseItem *arrow = new QGraphicsEllipseItem(presenter()->rootItem());
241 arrow->setPen(axis()->linePen());
241 arrow->setPen(axis()->linePen());
242 arrowGroup()->addToGroup(arrow);
242 arrowGroup()->addToGroup(arrow);
243 }
243 }
244
244
245 for (int i = 0; i < count; ++i) {
245 for (int i = 0; i < count; ++i) {
246 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
246 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
247 QGraphicsLineItem *grid = new QGraphicsLineItem(presenter()->rootItem());
247 QGraphicsLineItem *grid = new QGraphicsLineItem(presenter()->rootItem());
248 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
248 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
249 QGraphicsTextItem *title = titleItem();
249 QGraphicsTextItem *title = titleItem();
250 arrow->setPen(axis()->linePen());
250 arrow->setPen(axis()->linePen());
251 grid->setPen(axis()->gridLinePen());
251 grid->setPen(axis()->gridLinePen());
252 label->setFont(axis()->labelsFont());
252 label->setFont(axis()->labelsFont());
253 label->setDefaultTextColor(axis()->labelsBrush().color());
253 label->setDefaultTextColor(axis()->labelsBrush().color());
254 label->setRotation(axis()->labelsAngle());
254 label->setRotation(axis()->labelsAngle());
255 title->setFont(axis()->titleFont());
255 title->setFont(axis()->titleFont());
256 title->setDefaultTextColor(axis()->titleBrush().color());
256 title->setDefaultTextColor(axis()->titleBrush().color());
257 title->setHtml(axis()->titleText());
257 title->setHtml(axis()->titleText());
258 arrowGroup()->addToGroup(arrow);
258 arrowGroup()->addToGroup(arrow);
259 gridGroup()->addToGroup(grid);
259 gridGroup()->addToGroup(grid);
260 labelGroup()->addToGroup(label);
260 labelGroup()->addToGroup(label);
261 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
261 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
262 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
262 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
263 shade->setPen(axis()->shadesPen());
263 shade->setPen(axis()->shadesPen());
264 shade->setBrush(axis()->shadesBrush());
264 shade->setBrush(axis()->shadesBrush());
265 shadeGroup()->addToGroup(shade);
265 shadeGroup()->addToGroup(shade);
266 }
266 }
267 }
267 }
268 }
268 }
269
269
270 void PolarChartAxisAngular::handleArrowPenChanged(const QPen &pen)
270 void PolarChartAxisAngular::handleArrowPenChanged(const QPen &pen)
271 {
271 {
272 bool first = true;
272 bool first = true;
273 foreach (QGraphicsItem *item, arrowItems()) {
273 foreach (QGraphicsItem *item, arrowItems()) {
274 if (first) {
274 if (first) {
275 first = false;
275 first = false;
276 // First arrow item is the outer circle of axis
276 // First arrow item is the outer circle of axis
277 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
277 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
278 } else {
278 } else {
279 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
279 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
280 }
280 }
281 }
281 }
282 }
282 }
283
283
284 void PolarChartAxisAngular::handleGridPenChanged(const QPen &pen)
284 void PolarChartAxisAngular::handleGridPenChanged(const QPen &pen)
285 {
285 {
286 foreach (QGraphicsItem *item, gridItems())
286 foreach (QGraphicsItem *item, gridItems())
287 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
287 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
288 }
288 }
289
289
290 QSizeF PolarChartAxisAngular::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
290 QSizeF PolarChartAxisAngular::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
291 {
291 {
292 Q_UNUSED(which);
292 Q_UNUSED(which);
293 Q_UNUSED(constraint);
293 Q_UNUSED(constraint);
294 return QSizeF(-1, -1);
294 return QSizeF(-1, -1);
295 }
295 }
296
296
297 qreal PolarChartAxisAngular::preferredAxisRadius(const QSizeF &maxSize)
297 qreal PolarChartAxisAngular::preferredAxisRadius(const QSizeF &maxSize)
298 {
298 {
299 qreal radius = maxSize.height() / 2.0;
299 qreal radius = maxSize.height() / 2.0;
300 if (maxSize.width() < maxSize.height())
300 if (maxSize.width() < maxSize.height())
301 radius = maxSize.width() / 2.0;
301 radius = maxSize.width() / 2.0;
302
302
303 if (axis()->labelsVisible()) {
303 if (axis()->labelsVisible()) {
304 QVector<qreal> layout = calculateLayout();
304 QVector<qreal> layout = calculateLayout();
305 if (layout.isEmpty())
305 if (layout.isEmpty())
306 return radius;
306 return radius;
307
307
308 createAxisLabels(layout);
308 createAxisLabels(layout);
309 QStringList labelList = labels();
309 QStringList labelList = labels();
310 QFont font = axis()->labelsFont();
310 QFont font = axis()->labelsFont();
311
311
312 QRectF maxRect;
312 QRectF maxRect;
313 maxRect.setSize(maxSize);
313 maxRect.setSize(maxSize);
314 maxRect.moveCenter(QPointF(0.0, 0.0));
314 maxRect.moveCenter(QPointF(0.0, 0.0));
315
315
316 // This is a horrible way to find out the maximum radius for angular axis and its labels.
316 // This is a horrible way to find out the maximum radius for angular axis and its labels.
317 // It just increments the radius down until everyhing fits the constraint size.
317 // It just increments the radius down until everyhing fits the constraint size.
318 // Proper way would be to actually calculate it but this seems to work reasonably fast as it is.
318 // Proper way would be to actually calculate it but this seems to work reasonably fast as it is.
319 bool nextTickVisible = false;
319 bool nextTickVisible = false;
320 for (int i = 0; i < layout.size(); ) {
320 for (int i = 0; i < layout.size(); ) {
321 if ((i == layout.size() - 1)
321 if ((i == layout.size() - 1)
322 || layout.at(i + 1) < 0.0
322 || layout.at(i + 1) < 0.0
323 || layout.at(i + 1) > 360.0) {
323 || layout.at(i + 1) > 360.0) {
324 nextTickVisible = false;
324 nextTickVisible = false;
325 } else {
325 } else {
326 nextTickVisible = true;
326 nextTickVisible = true;
327 }
327 }
328
328
329 qreal labelCoordinate = layout.at(i);
329 qreal labelCoordinate = layout.at(i);
330 qreal labelVisible;
330 qreal labelVisible;
331
331
332 if (intervalAxis()) {
332 if (intervalAxis()) {
333 qreal farEdge;
333 qreal farEdge;
334 if (i == (layout.size() - 1))
334 if (i == (layout.size() - 1))
335 farEdge = 360.0;
335 farEdge = 360.0;
336 else
336 else
337 farEdge = qMin(qreal(360.0), layout.at(i + 1));
337 farEdge = qMin(qreal(360.0), layout.at(i + 1));
338
338
339 // Adjust the labelCoordinate to show it if next tick is visible
339 // Adjust the labelCoordinate to show it if next tick is visible
340 if (nextTickVisible)
340 if (nextTickVisible)
341 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
341 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
342
342
343 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
343 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
344 }
344 }
345
345
346 if (labelCoordinate < 0.0 || labelCoordinate > 360.0)
346 if (labelCoordinate < 0.0 || labelCoordinate > 360.0)
347 labelVisible = false;
347 labelVisible = false;
348 else
348 else
349 labelVisible = true;
349 labelVisible = true;
350
350
351 if (!labelVisible) {
351 if (!labelVisible) {
352 i++;
352 i++;
353 continue;
353 continue;
354 }
354 }
355
355
356 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
356 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
357 QPointF labelPoint = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate).p2();
357 QPointF labelPoint = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate).p2();
358
358
359 boundingRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
359 boundingRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
360 if (boundingRect.isEmpty() || maxRect.intersected(boundingRect) == boundingRect) {
360 if (boundingRect.isEmpty() || maxRect.intersected(boundingRect) == boundingRect) {
361 i++;
361 i++;
362 } else {
362 } else {
363 radius -= 1.0;
363 radius -= 1.0;
364 if (radius < 1.0) // safeguard
364 if (radius < 1.0) // safeguard
365 return 1.0;
365 return 1.0;
366 }
366 }
367 }
367 }
368 }
368 }
369
369
370 if (!axis()->titleText().isEmpty() && axis()->isTitleVisible()) {
370 if (!axis()->titleText().isEmpty() && axis()->isTitleVisible()) {
371 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
371 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
372
372
373 radius -= titlePadding() + (titleRect.height() / 2.0);
373 radius -= titlePadding() + (titleRect.height() / 2.0);
374 if (radius < 1.0) // safeguard
374 if (radius < 1.0) // safeguard
375 return 1.0;
375 return 1.0;
376 }
376 }
377
377
378 return radius;
378 return radius;
379 }
379 }
380
380
381 QRectF PolarChartAxisAngular::moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const
381 QRectF PolarChartAxisAngular::moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const
382 {
382 {
383 // TODO use fuzzy compare for "==" cases?
383 // TODO use fuzzy compare for "==" cases?
384 // TODO Adjust the rect position near 0, 90, 180, and 270 angles for smoother animation?
384 // TODO Adjust the rect position near 0, 90, 180, and 270 angles for smoother animation?
385 if (angularCoordinate == 0.0)
385 if (angularCoordinate == 0.0)
386 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
386 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
387 else if (angularCoordinate < 90.0)
387 else if (angularCoordinate < 90.0)
388 labelRect.moveBottomLeft(labelPoint);
388 labelRect.moveBottomLeft(labelPoint);
389 else if (angularCoordinate == 90.0)
389 else if (angularCoordinate == 90.0)
390 labelRect.moveCenter(labelPoint + QPointF(labelRect.width() / 2.0 + 2.0, 0)); // +2 so that it does not hit the radial axis
390 labelRect.moveCenter(labelPoint + QPointF(labelRect.width() / 2.0 + 2.0, 0)); // +2 so that it does not hit the radial axis
391 else if (angularCoordinate < 180.0)
391 else if (angularCoordinate < 180.0)
392 labelRect.moveTopLeft(labelPoint);
392 labelRect.moveTopLeft(labelPoint);
393 else if (angularCoordinate == 180.0)
393 else if (angularCoordinate == 180.0)
394 labelRect.moveCenter(labelPoint + QPointF(0, labelRect.height() / 2.0));
394 labelRect.moveCenter(labelPoint + QPointF(0, labelRect.height() / 2.0));
395 else if (angularCoordinate < 270.0)
395 else if (angularCoordinate < 270.0)
396 labelRect.moveTopRight(labelPoint);
396 labelRect.moveTopRight(labelPoint);
397 else if (angularCoordinate == 270.0)
397 else if (angularCoordinate == 270.0)
398 labelRect.moveCenter(labelPoint + QPointF(-labelRect.width() / 2.0 - 2.0, 0)); // -2 so that it does not hit the radial axis
398 labelRect.moveCenter(labelPoint + QPointF(-labelRect.width() / 2.0 - 2.0, 0)); // -2 so that it does not hit the radial axis
399 else if (angularCoordinate < 360.0)
399 else if (angularCoordinate < 360.0)
400 labelRect.moveBottomRight(labelPoint);
400 labelRect.moveBottomRight(labelPoint);
401 else
401 else
402 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
402 labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
403 return labelRect;
403 return labelRect;
404 }
404 }
405
405
406 #include "moc_polarchartaxisangular_p.cpp"
406 #include "moc_polarchartaxisangular_p.cpp"
407
407
408 QTCOMMERCIALCHART_END_NAMESPACE
408 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,288 +1,288
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "polarchartaxisradial_p.h"
21 #include "polarchartaxisradial_p.h"
22 #include "chartpresenter_p.h"
22 #include "chartpresenter_p.h"
23 #include "abstractchartlayout_p.h"
23 #include "abstractchartlayout_p.h"
24 #include "qabstractaxis_p.h"
24 #include "qabstractaxis_p.h"
25 #include "linearrowitem_p.h"
25 #include "linearrowitem_p.h"
26
26
27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27 QTCOMMERCIALCHART_BEGIN_NAMESPACE
28
28
29 PolarChartAxisRadial::PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
29 PolarChartAxisRadial::PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
30 : PolarChartAxis(axis, item, intervalAxis)
30 : PolarChartAxis(axis, item, intervalAxis)
31 {
31 {
32 }
32 }
33
33
34 PolarChartAxisRadial::~PolarChartAxisRadial()
34 PolarChartAxisRadial::~PolarChartAxisRadial()
35 {
35 {
36 }
36 }
37
37
38 void PolarChartAxisRadial::updateGeometry()
38 void PolarChartAxisRadial::updateGeometry()
39 {
39 {
40 const QVector<qreal> &layout = this->layout();
40 const QVector<qreal> &layout = this->layout();
41 if (layout.isEmpty())
41 if (layout.isEmpty())
42 return;
42 return;
43
43
44 createAxisLabels(layout);
44 createAxisLabels(layout);
45 QStringList labelList = labels();
45 QStringList labelList = labels();
46 QPointF center = axisGeometry().center();
46 QPointF center = axisGeometry().center();
47 QList<QGraphicsItem *> arrowItemList = arrowItems();
47 QList<QGraphicsItem *> arrowItemList = arrowItems();
48 QList<QGraphicsItem *> gridItemList = gridItems();
48 QList<QGraphicsItem *> gridItemList = gridItems();
49 QList<QGraphicsItem *> labelItemList = labelItems();
49 QList<QGraphicsItem *> labelItemList = labelItems();
50 QList<QGraphicsItem *> shadeItemList = shadeItems();
50 QList<QGraphicsItem *> shadeItemList = shadeItems();
51 QGraphicsTextItem* title = titleItem();
51 QGraphicsTextItem* title = titleItem();
52 qreal radius = axisGeometry().height() / 2.0;
52 qreal radius = axisGeometry().height() / 2.0;
53
53
54 QLineF line(center, center + QPointF(0, -radius));
54 QLineF line(center, center + QPointF(0, -radius));
55 QGraphicsLineItem *axisLine = static_cast<QGraphicsLineItem *>(arrowItemList.at(0));
55 QGraphicsLineItem *axisLine = static_cast<QGraphicsLineItem *>(arrowItemList.at(0));
56 axisLine->setLine(line);
56 axisLine->setLine(line);
57
57
58 QRectF previousLabelRect;
58 QRectF previousLabelRect;
59 bool firstShade = true;
59 bool firstShade = true;
60 bool nextTickVisible = false;
60 bool nextTickVisible = false;
61 if (layout.size())
61 if (layout.size())
62 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > radius);
62 nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > radius);
63
63
64 for (int i = 0; i < layout.size(); ++i) {
64 for (int i = 0; i < layout.size(); ++i) {
65 qreal radialCoordinate = layout.at(i);
65 qreal radialCoordinate = layout.at(i);
66
66
67 QGraphicsEllipseItem *gridItem = static_cast<QGraphicsEllipseItem *>(gridItemList.at(i));
67 QGraphicsEllipseItem *gridItem = static_cast<QGraphicsEllipseItem *>(gridItemList.at(i));
68 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
68 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
69 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
69 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labelItemList.at(i));
70 QGraphicsPathItem *shadeItem = 0;
70 QGraphicsPathItem *shadeItem = 0;
71 if (i == 0)
71 if (i == 0)
72 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
72 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
73 else if (i % 2)
73 else if (i % 2)
74 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
74 shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
75
75
76 // Ignore ticks outside valid range
76 // Ignore ticks outside valid range
77 bool currentTickVisible = nextTickVisible;
77 bool currentTickVisible = nextTickVisible;
78 if ((i == layout.size() - 1)
78 if ((i == layout.size() - 1)
79 || layout.at(i + 1) < 0.0
79 || layout.at(i + 1) < 0.0
80 || layout.at(i + 1) > radius) {
80 || layout.at(i + 1) > radius) {
81 nextTickVisible = false;
81 nextTickVisible = false;
82 } else {
82 } else {
83 nextTickVisible = true;
83 nextTickVisible = true;
84 }
84 }
85
85
86 qreal labelCoordinate = radialCoordinate;
86 qreal labelCoordinate = radialCoordinate;
87 qreal labelVisible = currentTickVisible;
87 qreal labelVisible = currentTickVisible;
88 qreal labelPad = labelPadding() / 2.0;
88 qreal labelPad = labelPadding() / 2.0;
89 if (intervalAxis()) {
89 if (intervalAxis()) {
90 qreal farEdge;
90 qreal farEdge;
91 if (i == (layout.size() - 1))
91 if (i == (layout.size() - 1))
92 farEdge = radius;
92 farEdge = radius;
93 else
93 else
94 farEdge = qMin(radius, layout.at(i + 1));
94 farEdge = qMin(radius, layout.at(i + 1));
95
95
96 // Adjust the labelCoordinate to show it if next tick is visible
96 // Adjust the labelCoordinate to show it if next tick is visible
97 if (nextTickVisible)
97 if (nextTickVisible)
98 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
98 labelCoordinate = qMax(qreal(0.0), labelCoordinate);
99
99
100 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
100 labelCoordinate = (labelCoordinate + farEdge) / 2.0;
101 if (labelCoordinate > 0.0 && labelCoordinate < radius)
101 if (labelCoordinate > 0.0 && labelCoordinate < radius)
102 labelVisible = true;
102 labelVisible = true;
103 else
103 else
104 labelVisible = false;
104 labelVisible = false;
105 }
105 }
106
106
107 // Radial axis label
107 // Radial axis label
108 if (axis()->labelsVisible() && labelVisible) {
108 if (axis()->labelsVisible() && labelVisible) {
109 labelItem->setHtml(labelList.at(i));
109 labelItem->setHtml(labelList.at(i));
110 QRectF labelRect = labelItem->boundingRect();
110 QRectF labelRect = labelItem->boundingRect();
111 QPointF labelCenter = labelRect.center();
111 QPointF labelCenter = labelRect.center();
112 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
112 labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
113 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
113 QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(), labelList.at(i), axis()->labelsAngle());
114 boundingRect.moveCenter(labelCenter);
114 boundingRect.moveCenter(labelCenter);
115 QPointF positionDiff(labelRect.topLeft() - boundingRect.topLeft());
115 QPointF positionDiff(labelRect.topLeft() - boundingRect.topLeft());
116 QPointF labelPoint = center;
116 QPointF labelPoint = center;
117 if (intervalAxis())
117 if (intervalAxis())
118 labelPoint += QPointF(labelPad, -labelCoordinate - (boundingRect.height() / 2.0));
118 labelPoint += QPointF(labelPad, -labelCoordinate - (boundingRect.height() / 2.0));
119 else
119 else
120 labelPoint += QPointF(labelPad, labelPad - labelCoordinate);
120 labelPoint += QPointF(labelPad, labelPad - labelCoordinate);
121 labelRect.moveTopLeft(labelPoint);
121 labelRect.moveTopLeft(labelPoint);
122 labelItem->setPos(labelRect.topLeft() + positionDiff);
122 labelItem->setPos(labelRect.topLeft() + positionDiff);
123
123
124 // Label overlap detection
124 // Label overlap detection
125 labelRect.setSize(boundingRect.size());
125 labelRect.setSize(boundingRect.size());
126 if ((i && previousLabelRect.intersects(labelRect))
126 if ((i && previousLabelRect.intersects(labelRect))
127 || !axisGeometry().contains(labelRect)) {
127 || !axisGeometry().contains(labelRect)) {
128 labelVisible = false;
128 labelVisible = false;
129 } else {
129 } else {
130 previousLabelRect = labelRect;
130 previousLabelRect = labelRect;
131 labelVisible = true;
131 labelVisible = true;
132 }
132 }
133 }
133 }
134
134
135 labelItem->setVisible(labelVisible);
135 labelItem->setVisible(labelVisible);
136 if (!currentTickVisible) {
136 if (!currentTickVisible) {
137 gridItem->setVisible(false);
137 gridItem->setVisible(false);
138 tickItem->setVisible(false);
138 tickItem->setVisible(false);
139 if (shadeItem)
139 if (shadeItem)
140 shadeItem->setVisible(false);
140 shadeItem->setVisible(false);
141 continue;
141 continue;
142 }
142 }
143
143
144 // Radial grid line
144 // Radial grid line
145 QRectF gridRect;
145 QRectF gridRect;
146 gridRect.setWidth(radialCoordinate * 2.0);
146 gridRect.setWidth(radialCoordinate * 2.0);
147 gridRect.setHeight(radialCoordinate * 2.0);
147 gridRect.setHeight(radialCoordinate * 2.0);
148 gridRect.moveCenter(center);
148 gridRect.moveCenter(center);
149
149
150 gridItem->setRect(gridRect);
150 gridItem->setRect(gridRect);
151 gridItem->setVisible(true);
151 gridItem->setVisible(true);
152
152
153 // Tick
153 // Tick
154 QLineF tickLine(-tickWidth(), 0.0, tickWidth(), 0.0);
154 QLineF tickLine(-tickWidth(), 0.0, tickWidth(), 0.0);
155 tickLine.translate(center.rx(), gridRect.top());
155 tickLine.translate(center.rx(), gridRect.top());
156 tickItem->setLine(tickLine);
156 tickItem->setLine(tickLine);
157 tickItem->setVisible(true);
157 tickItem->setVisible(true);
158
158
159 // Shades
159 // Shades
160 if (i % 2 || (i == 0 && !nextTickVisible)) {
160 if (i % 2 || (i == 0 && !nextTickVisible)) {
161 QPainterPath path;
161 QPainterPath path;
162 if (i == 0) {
162 if (i == 0) {
163 // If first tick is also the last, we need to custom fill the inner circle
163 // If first tick is also the last, we need to custom fill the inner circle
164 // or it won't get filled.
164 // or it won't get filled.
165 QRectF innerCircle(0.0, 0.0, layout.at(0) * 2.0, layout.at(0) * 2.0);
165 QRectF innerCircle(0.0, 0.0, layout.at(0) * 2.0, layout.at(0) * 2.0);
166 innerCircle.moveCenter(center);
166 innerCircle.moveCenter(center);
167 path.addEllipse(innerCircle);
167 path.addEllipse(innerCircle);
168 } else {
168 } else {
169 QRectF otherGridRect;
169 QRectF otherGridRect;
170 if (!nextTickVisible) { // Last visible tick
170 if (!nextTickVisible) { // Last visible tick
171 otherGridRect = axisGeometry();
171 otherGridRect = axisGeometry();
172 } else {
172 } else {
173 qreal otherGridRectDimension = layout.at(i + 1) * 2.0;
173 qreal otherGridRectDimension = layout.at(i + 1) * 2.0;
174 otherGridRect.setWidth(otherGridRectDimension);
174 otherGridRect.setWidth(otherGridRectDimension);
175 otherGridRect.setHeight(otherGridRectDimension);
175 otherGridRect.setHeight(otherGridRectDimension);
176 otherGridRect.moveCenter(center);
176 otherGridRect.moveCenter(center);
177 }
177 }
178 path.addEllipse(gridRect);
178 path.addEllipse(gridRect);
179 path.addEllipse(otherGridRect);
179 path.addEllipse(otherGridRect);
180
180
181 // Add additional shading in first visible shade item if there is a partial tick
181 // Add additional shading in first visible shade item if there is a partial tick
182 // to be filled at the center (log & category axes)
182 // to be filled at the center (log & category axes)
183 if (firstShade) {
183 if (firstShade) {
184 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
184 QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
185 if (layout.at(i - 1) > 0.0) {
185 if (layout.at(i - 1) > 0.0) {
186 QRectF innerCircle(0.0, 0.0, layout.at(i - 1) * 2.0, layout.at(i - 1) * 2.0);
186 QRectF innerCircle(0.0, 0.0, layout.at(i - 1) * 2.0, layout.at(i - 1) * 2.0);
187 innerCircle.moveCenter(center);
187 innerCircle.moveCenter(center);
188 QPainterPath specialPath;
188 QPainterPath specialPath;
189 specialPath.addEllipse(innerCircle);
189 specialPath.addEllipse(innerCircle);
190 specialShadeItem->setPath(specialPath);
190 specialShadeItem->setPath(specialPath);
191 specialShadeItem->setVisible(true);
191 specialShadeItem->setVisible(true);
192 } else {
192 } else {
193 specialShadeItem->setVisible(false);
193 specialShadeItem->setVisible(false);
194 }
194 }
195 }
195 }
196 }
196 }
197 shadeItem->setPath(path);
197 shadeItem->setPath(path);
198 shadeItem->setVisible(true);
198 shadeItem->setVisible(true);
199 firstShade = false;
199 firstShade = false;
200 }
200 }
201 }
201 }
202
202
203 // Title, along the 0 axis
203 // Title, along the 0 axis
204 QString titleText = axis()->titleText();
204 QString titleText = axis()->titleText();
205 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
205 if (!titleText.isEmpty() && axis()->isTitleVisible()) {
206 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), radius, Qt::Horizontal, QRectF()));
206 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), radius, Qt::Horizontal, QRectF()));
207
207
208 QRectF titleBoundingRect = title->boundingRect();
208 QRectF titleBoundingRect = title->boundingRect();
209 QPointF titleCenter = titleBoundingRect.center();
209 QPointF titleCenter = titleBoundingRect.center();
210 QPointF arrowCenter = axisLine->boundingRect().center();
210 QPointF arrowCenter = axisLine->boundingRect().center();
211 QPointF titleCenterDiff = arrowCenter - titleCenter;
211 QPointF titleCenterDiff = arrowCenter - titleCenter;
212 title->setPos(titleCenterDiff.x() - qreal(titlePadding()) - (titleBoundingRect.height() / 2.0), titleCenterDiff.y());
212 title->setPos(titleCenterDiff.x() - titlePadding() - (titleBoundingRect.height() / 2.0), titleCenterDiff.y());
213 title->setTransformOriginPoint(titleCenter);
213 title->setTransformOriginPoint(titleCenter);
214 title->setRotation(270.0);
214 title->setRotation(270.0);
215 }
215 }
216
216
217 QGraphicsLayoutItem::updateGeometry();
217 QGraphicsLayoutItem::updateGeometry();
218 }
218 }
219
219
220 Qt::Orientation PolarChartAxisRadial::orientation() const
220 Qt::Orientation PolarChartAxisRadial::orientation() const
221 {
221 {
222 return Qt::Vertical;
222 return Qt::Vertical;
223 }
223 }
224
224
225 void PolarChartAxisRadial::createItems(int count)
225 void PolarChartAxisRadial::createItems(int count)
226 {
226 {
227 if (arrowItems().count() == 0) {
227 if (arrowItems().count() == 0) {
228 // radial axis center line
228 // radial axis center line
229 QGraphicsLineItem *arrow = new LineArrowItem(this, presenter()->rootItem());
229 QGraphicsLineItem *arrow = new LineArrowItem(this, presenter()->rootItem());
230 arrow->setPen(axis()->linePen());
230 arrow->setPen(axis()->linePen());
231 arrowGroup()->addToGroup(arrow);
231 arrowGroup()->addToGroup(arrow);
232 }
232 }
233
233
234 for (int i = 0; i < count; ++i) {
234 for (int i = 0; i < count; ++i) {
235 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
235 QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
236 QGraphicsEllipseItem *grid = new QGraphicsEllipseItem(presenter()->rootItem());
236 QGraphicsEllipseItem *grid = new QGraphicsEllipseItem(presenter()->rootItem());
237 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
237 QGraphicsTextItem *label = new QGraphicsTextItem(presenter()->rootItem());
238 QGraphicsTextItem *title = titleItem();
238 QGraphicsTextItem *title = titleItem();
239 arrow->setPen(axis()->linePen());
239 arrow->setPen(axis()->linePen());
240 grid->setPen(axis()->gridLinePen());
240 grid->setPen(axis()->gridLinePen());
241 label->setFont(axis()->labelsFont());
241 label->setFont(axis()->labelsFont());
242 label->setDefaultTextColor(axis()->labelsBrush().color());
242 label->setDefaultTextColor(axis()->labelsBrush().color());
243 label->setRotation(axis()->labelsAngle());
243 label->setRotation(axis()->labelsAngle());
244 title->setFont(axis()->titleFont());
244 title->setFont(axis()->titleFont());
245 title->setDefaultTextColor(axis()->titleBrush().color());
245 title->setDefaultTextColor(axis()->titleBrush().color());
246 title->setHtml(axis()->titleText());
246 title->setHtml(axis()->titleText());
247 arrowGroup()->addToGroup(arrow);
247 arrowGroup()->addToGroup(arrow);
248 gridGroup()->addToGroup(grid);
248 gridGroup()->addToGroup(grid);
249 labelGroup()->addToGroup(label);
249 labelGroup()->addToGroup(label);
250 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
250 if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
251 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
251 QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
252 shade->setPen(axis()->shadesPen());
252 shade->setPen(axis()->shadesPen());
253 shade->setBrush(axis()->shadesBrush());
253 shade->setBrush(axis()->shadesBrush());
254 shadeGroup()->addToGroup(shade);
254 shadeGroup()->addToGroup(shade);
255 }
255 }
256 }
256 }
257 }
257 }
258
258
259 void PolarChartAxisRadial::handleArrowPenChanged(const QPen &pen)
259 void PolarChartAxisRadial::handleArrowPenChanged(const QPen &pen)
260 {
260 {
261 foreach (QGraphicsItem *item, arrowItems())
261 foreach (QGraphicsItem *item, arrowItems())
262 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
262 static_cast<QGraphicsLineItem *>(item)->setPen(pen);
263 }
263 }
264
264
265 void PolarChartAxisRadial::handleGridPenChanged(const QPen &pen)
265 void PolarChartAxisRadial::handleGridPenChanged(const QPen &pen)
266 {
266 {
267 foreach (QGraphicsItem *item, gridItems())
267 foreach (QGraphicsItem *item, gridItems())
268 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
268 static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
269 }
269 }
270
270
271 QSizeF PolarChartAxisRadial::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
271 QSizeF PolarChartAxisRadial::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
272 {
272 {
273 Q_UNUSED(which);
273 Q_UNUSED(which);
274 Q_UNUSED(constraint);
274 Q_UNUSED(constraint);
275 return QSizeF(-1.0, -1.0);
275 return QSizeF(-1.0, -1.0);
276 }
276 }
277
277
278 qreal PolarChartAxisRadial::preferredAxisRadius(const QSizeF &maxSize)
278 qreal PolarChartAxisRadial::preferredAxisRadius(const QSizeF &maxSize)
279 {
279 {
280 qreal radius = maxSize.height() / 2.0;
280 qreal radius = maxSize.height() / 2.0;
281 if (maxSize.width() < maxSize.height())
281 if (maxSize.width() < maxSize.height())
282 radius = maxSize.width() / 2.0;
282 radius = maxSize.width() / 2.0;
283 return radius;
283 return radius;
284 }
284 }
285
285
286 #include "moc_polarchartaxisradial_p.cpp"
286 #include "moc_polarchartaxisradial_p.cpp"
287
287
288 QTCOMMERCIALCHART_END_NAMESPACE
288 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,211 +1,228
1 /****************************************************************************
1 /****************************************************************************
2 **
2 **
3 ** Copyright (C) 2013 Digia Plc
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
8 **
9 ** $QT_BEGIN_LICENSE$
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
13 ** a written agreement between you and Digia.
14 **
14 **
15 ** If you have questions regarding the use of this file, please use
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
17 ** $QT_END_LICENSE$
18 **
18 **
19 ****************************************************************************/
19 ****************************************************************************/
20
20
21 #include "verticalaxis_p.h"
21 #include "verticalaxis_p.h"
22 #include "qabstractaxis.h"
22 #include "qabstractaxis.h"
23 #include "chartpresenter_p.h"
23 #include "chartpresenter_p.h"
24 #include <QDebug>
24 #include <QDebug>
25
25
26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
26 QTCOMMERCIALCHART_BEGIN_NAMESPACE
27
27
28 VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
28 VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
29 : CartesianChartAxis(axis, item, intervalAxis)
29 : CartesianChartAxis(axis, item, intervalAxis)
30 {
30 {
31 }
31 }
32
32
33 VerticalAxis::~VerticalAxis()
33 VerticalAxis::~VerticalAxis()
34 {
34 {
35 }
35 }
36
36
37 void VerticalAxis::updateGeometry()
37 void VerticalAxis::updateGeometry()
38 {
38 {
39 const QVector<qreal> &layout = ChartAxisElement::layout();
39 const QVector<qreal> &layout = ChartAxisElement::layout();
40
40
41 if (layout.isEmpty())
41 if (layout.isEmpty())
42 return;
42 return;
43
43
44 QStringList labelList = labels();
44 QStringList labelList = labels();
45
45
46 QList<QGraphicsItem *> lines = gridItems();
46 QList<QGraphicsItem *> lines = gridItems();
47 QList<QGraphicsItem *> labels = labelItems();
47 QList<QGraphicsItem *> labels = labelItems();
48 QList<QGraphicsItem *> shades = shadeItems();
48 QList<QGraphicsItem *> shades = shadeItems();
49 QList<QGraphicsItem *> arrow = arrowItems();
49 QList<QGraphicsItem *> arrow = arrowItems();
50 QGraphicsTextItem *title = titleItem();
50 QGraphicsTextItem *title = titleItem();
51
51
52 Q_ASSERT(labels.size() == labelList.size());
52 Q_ASSERT(labels.size() == labelList.size());
53 Q_ASSERT(layout.size() == labelList.size());
53 Q_ASSERT(layout.size() == labelList.size());
54
54
55 const QRectF &axisRect = axisGeometry();
55 const QRectF &axisRect = axisGeometry();
56 const QRectF &gridRect = gridGeometry();
56 const QRectF &gridRect = gridGeometry();
57
57
58 qreal height = axisRect.bottom();
58 qreal height = axisRect.bottom();
59
59
60
60
61 //arrow
61 //arrow
62 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(arrow.at(0));
62 QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(arrow.at(0));
63
63
64 //arrow position
64 //arrow position
65 if (axis()->alignment() == Qt::AlignLeft)
65 if (axis()->alignment() == Qt::AlignLeft)
66 arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom());
66 arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom());
67 else if (axis()->alignment() == Qt::AlignRight)
67 else if (axis()->alignment() == Qt::AlignRight)
68 arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom());
68 arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom());
69
69
70 //title
70 //title
71 int titlePad = 0;
72 QRectF titleBoundingRect;
71 QRectF titleBoundingRect;
73 QString titleText = axis()->titleText();
72 QString titleText = axis()->titleText();
73 qreal availableSpace = axisRect.width() - labelPadding();
74 if (!titleText.isEmpty() && titleItem()->isVisible()) {
74 if (!titleText.isEmpty() && titleItem()->isVisible()) {
75 title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0), gridRect.height(), Qt::Horizontal, QRectF()));
75 availableSpace -= titlePadding() * 2.0;
76 qreal minimumLabelWidth = ChartPresenter::textBoundingRect(axis()->labelsFont(), "...").width();
77 QString truncatedTitle = ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
78 gridRect.height(), Qt::Horizontal, titleBoundingRect);
79 qreal titleSpace = availableSpace - minimumLabelWidth;
80 if (titleSpace < titleBoundingRect.width()) {
81 // Need to also truncate title vertically (multiline title)
82 bool skip = false;
83 if (truncatedTitle.endsWith("...")) {
84 if (truncatedTitle.size() == 3)
85 skip = true; // Already truncated to minimum
86 else
87 truncatedTitle.chop(3);
88 }
89 if (!skip)
90 truncatedTitle = ChartPresenter::truncatedText(axis()->titleFont(), truncatedTitle, qreal(0.0),
91 titleSpace, Qt::Vertical, titleBoundingRect);
92 }
93 title->setHtml(truncatedTitle);
76
94
77 titlePad = titlePadding();
78 titleBoundingRect = title->boundingRect();
95 titleBoundingRect = title->boundingRect();
79
96
80 QPointF center = gridRect.center() - titleBoundingRect.center();
97 QPointF center = gridRect.center() - titleBoundingRect.center();
81 if (axis()->alignment() == Qt::AlignLeft) {
98 if (axis()->alignment() == Qt::AlignLeft)
82 title->setPos(axisRect.left() - titleBoundingRect.width() / 2 + titleBoundingRect.height() / 2 + titlePad, center.y());
99 title->setPos(axisRect.left() - titleBoundingRect.width() / 2.0 + titleBoundingRect.height() / 2.0 + titlePadding(), center.y());
83 }
100 else if (axis()->alignment() == Qt::AlignRight)
84 else if (axis()->alignment() == Qt::AlignRight) {
101 title->setPos(axisRect.right() - titleBoundingRect.width() / 2.0 - titleBoundingRect.height() / 2.0 - titlePadding(), center.y());
85 title->setPos(axisRect.right() - titleBoundingRect.width() / 2 - titleBoundingRect.height() / 2 - titlePad, center.y());
102
86 }
87 title->setTransformOriginPoint(titleBoundingRect.center());
103 title->setTransformOriginPoint(titleBoundingRect.center());
88 title->setRotation(270);
104 title->setRotation(270);
105
106 availableSpace -= titleBoundingRect.height();
89 }
107 }
90
108
91 for (int i = 0; i < layout.size(); ++i) {
109 for (int i = 0; i < layout.size(); ++i) {
92 //items
110 //items
93 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i));
111 QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i));
94 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrow.at(i + 1));
112 QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrow.at(i + 1));
95 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
113 QGraphicsTextItem *labelItem = static_cast<QGraphicsTextItem *>(labels.at(i));
96
114
97 //grid line
115 //grid line
98 gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
116 gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
99
117
100 //label text wrapping
118 //label text wrapping
101 QString text = labelList.at(i);
119 QString text = labelList.at(i);
102 QRectF boundingRect;
120 QRectF boundingRect;
103 qreal size = axisRect.right() - axisRect.left() - labelPadding() - titleBoundingRect.height() - (titlePad * 2);
104 labelItem->setHtml(ChartPresenter::truncatedText(axis()->labelsFont(), text, axis()->labelsAngle(),
121 labelItem->setHtml(ChartPresenter::truncatedText(axis()->labelsFont(), text, axis()->labelsAngle(),
105 size, Qt::Horizontal, boundingRect));
122 availableSpace, Qt::Horizontal, boundingRect));
106
123
107 //label transformation origin point
124 //label transformation origin point
108 const QRectF &rect = labelItem->boundingRect();
125 const QRectF &rect = labelItem->boundingRect();
109 QPointF center = rect.center();
126 QPointF center = rect.center();
110 labelItem->setTransformOriginPoint(center.x(), center.y());
127 labelItem->setTransformOriginPoint(center.x(), center.y());
111 int widthDiff = rect.width() - boundingRect.width();
128 qreal widthDiff = rect.width() - boundingRect.width();
112
129
113 //ticks and label position
130 //ticks and label position
114 if (axis()->alignment() == Qt::AlignLeft) {
131 if (axis()->alignment() == Qt::AlignLeft) {
115 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2) - labelPadding(), layout[i] - center.y());
132 labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2.0) - labelPadding(), layout[i] - center.y());
116 tickItem->setLine(axisRect.right() - labelPadding(), layout[i], axisRect.right(), layout[i]);
133 tickItem->setLine(axisRect.right() - labelPadding(), layout[i], axisRect.right(), layout[i]);
117 } else if (axis()->alignment() == Qt::AlignRight) {
134 } else if (axis()->alignment() == Qt::AlignRight) {
118 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2), layout[i] - center.y());
135 labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2.0), layout[i] - center.y());
119 tickItem->setLine(axisRect.left(), layout[i], axisRect.left() + labelPadding(), layout[i]);
136 tickItem->setLine(axisRect.left(), layout[i], axisRect.left() + labelPadding(), layout[i]);
120 }
137 }
121
138
122 //label in between
139 //label in between
123 bool forceHide = false;
140 bool forceHide = false;
124 if (intervalAxis() && (i + 1) != layout.size()) {
141 if (intervalAxis() && (i + 1) != layout.size()) {
125 qreal lowerBound = qMin(layout[i], gridRect.bottom());
142 qreal lowerBound = qMin(layout[i], gridRect.bottom());
126 qreal upperBound = qMax(layout[i + 1], gridRect.top());
143 qreal upperBound = qMax(layout[i + 1], gridRect.top());
127 const qreal delta = lowerBound - upperBound;
144 const qreal delta = lowerBound - upperBound;
128 // Hide label in case visible part of the category at the grid edge is too narrow
145 // Hide label in case visible part of the category at the grid edge is too narrow
129 if (delta < boundingRect.height()
146 if (delta < boundingRect.height()
130 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())) {
147 && (lowerBound == gridRect.bottom() || upperBound == gridRect.top())) {
131 forceHide = true;
148 forceHide = true;
132 } else {
149 } else {
133 labelItem->setPos(labelItem->pos().x() , lowerBound - (delta / 2.0) - center.y());
150 labelItem->setPos(labelItem->pos().x() , lowerBound - (delta / 2.0) - center.y());
134 }
151 }
135 }
152 }
136
153
137 //label overlap detection - compensate one pixel for rounding errors
154 //label overlap detection - compensate one pixel for rounding errors
138 if (labelItem->pos().y() + boundingRect.height() > height || forceHide ||
155 if (labelItem->pos().y() + boundingRect.height() > height || forceHide ||
139 (labelItem->pos().y() + (boundingRect.height() / 2.0) - 1.0) > axisRect.bottom() ||
156 (labelItem->pos().y() + (boundingRect.height() / 2.0) - 1.0) > axisRect.bottom() ||
140 labelItem->pos().y() + (boundingRect.height() / 2.0) < (axisRect.top() - 1.0)) {
157 labelItem->pos().y() + (boundingRect.height() / 2.0) < (axisRect.top() - 1.0)) {
141 labelItem->setVisible(false);
158 labelItem->setVisible(false);
142 }
159 }
143 else {
160 else {
144 labelItem->setVisible(true);
161 labelItem->setVisible(true);
145 height=labelItem->pos().y();
162 height=labelItem->pos().y();
146 }
163 }
147
164
148 //shades
165 //shades
149 if ((i + 1) % 2 && i > 1) {
166 if ((i + 1) % 2 && i > 1) {
150 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
167 QGraphicsRectItem *rectItem = static_cast<QGraphicsRectItem *>(shades.at(i / 2 - 1));
151 qreal lowerBound = qMin(layout[i - 1], gridRect.bottom());
168 qreal lowerBound = qMin(layout[i - 1], gridRect.bottom());
152 qreal upperBound = qMax(layout[i], gridRect.top());
169 qreal upperBound = qMax(layout[i], gridRect.top());
153 rectItem->setRect(gridRect.left(), upperBound, gridRect.width(), lowerBound - upperBound);
170 rectItem->setRect(gridRect.left(), upperBound, gridRect.width(), lowerBound - upperBound);
154 if (rectItem->rect().height() <= 0.0)
171 if (rectItem->rect().height() <= 0.0)
155 rectItem->setVisible(false);
172 rectItem->setVisible(false);
156 else
173 else
157 rectItem->setVisible(true);
174 rectItem->setVisible(true);
158 }
175 }
159
176
160 // check if the grid line and the axis tick should be shown
177 // check if the grid line and the axis tick should be shown
161 qreal y = gridItem->line().p1().y();
178 qreal y = gridItem->line().p1().y();
162 if ((y < gridRect.top() || y > gridRect.bottom()))
179 if ((y < gridRect.top() || y > gridRect.bottom()))
163 {
180 {
164 gridItem->setVisible(false);
181 gridItem->setVisible(false);
165 tickItem->setVisible(false);
182 tickItem->setVisible(false);
166 }else{
183 }else{
167 gridItem->setVisible(true);
184 gridItem->setVisible(true);
168 tickItem->setVisible(true);
185 tickItem->setVisible(true);
169 }
186 }
170
187
171 }
188 }
172 //begin/end grid line in case labels between
189 //begin/end grid line in case labels between
173 if (intervalAxis()) {
190 if (intervalAxis()) {
174 QGraphicsLineItem *gridLine;
191 QGraphicsLineItem *gridLine;
175 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
192 gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
176 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
193 gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
177 gridLine->setVisible(true);
194 gridLine->setVisible(true);
178 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size() + 1));
195 gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size() + 1));
179 gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
196 gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
180 gridLine->setVisible(true);
197 gridLine->setVisible(true);
181 }
198 }
182 }
199 }
183
200
184 QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
201 QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
185 {
202 {
186 Q_UNUSED(constraint);
203 Q_UNUSED(constraint);
187 QSizeF sh(0, 0);
204 QSizeF sh(0, 0);
188
205
189 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
206 if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
190 return sh;
207 return sh;
191
208
192 switch (which) {
209 switch (which) {
193 case Qt::MinimumSize: {
210 case Qt::MinimumSize: {
194 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), "...");
211 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), "...");
195 sh = QSizeF(titleRect.height() + (titlePadding() * 2), titleRect.width());
212 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
196 break;
213 break;
197 }
214 }
198 case Qt::MaximumSize:
215 case Qt::MaximumSize:
199 case Qt::PreferredSize: {
216 case Qt::PreferredSize: {
200 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
217 QRectF titleRect = ChartPresenter::textBoundingRect(axis()->titleFont(), axis()->titleText());
201 sh = QSizeF(titleRect.height() + (titlePadding() * 2), titleRect.width());
218 sh = QSizeF(titleRect.height() + (titlePadding() * 2.0), titleRect.width());
202 break;
219 break;
203 }
220 }
204 default:
221 default:
205 break;
222 break;
206 }
223 }
207
224
208 return sh;
225 return sh;
209 }
226 }
210
227
211 QTCOMMERCIALCHART_END_NAMESPACE
228 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now