summaryrefslogtreecommitdiffstats
path: root/src/charts/areachart/areachartitem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/charts/areachart/areachartitem.cpp')
-rw-r--r--src/charts/areachart/areachartitem.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/charts/areachart/areachartitem.cpp b/src/charts/areachart/areachartitem.cpp
new file mode 100644
index 00000000..cf2d0e8f
--- /dev/null
+++ b/src/charts/areachart/areachartitem.cpp
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the Qt Enterprise Charts Add-on.
+**
+** $QT_BEGIN_LICENSE$
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "areachartitem_p.h"
+#include "qareaseries.h"
+#include "qareaseries_p.h"
+#include "qlineseries.h"
+#include "chartpresenter_p.h"
+#include "abstractdomain_p.h"
+#include <QPainter>
+#include <QGraphicsSceneMouseEvent>
+#include <QDebug>
+
+
+QT_CHARTS_BEGIN_NAMESPACE
+
+AreaChartItem::AreaChartItem(QAreaSeries *areaSeries, QGraphicsItem* item)
+ : ChartItem(areaSeries->d_func(),item),
+ m_series(areaSeries),
+ m_upper(0),
+ m_lower(0),
+ m_pointsVisible(false),
+ m_pointLabelsVisible(false),
+ m_pointLabelsFormat(areaSeries->pointLabelsFormat()),
+ m_pointLabelsFont(areaSeries->pointLabelsFont()),
+ m_pointLabelsColor(areaSeries->pointLabelsColor())
+{
+ setAcceptHoverEvents(true);
+ setZValue(ChartPresenter::LineChartZValue);
+ if (m_series->upperSeries())
+ m_upper = new AreaBoundItem(this, m_series->upperSeries());
+ if (m_series->lowerSeries())
+ m_lower = new AreaBoundItem(this, m_series->lowerSeries());
+
+ QObject::connect(m_series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated()));
+ QObject::connect(m_series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
+ QObject::connect(m_series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated()));
+ QObject::connect(this, SIGNAL(clicked(QPointF)), areaSeries, SIGNAL(clicked(QPointF)));
+ QObject::connect(this, SIGNAL(hovered(QPointF,bool)), areaSeries, SIGNAL(hovered(QPointF,bool)));
+ QObject::connect(areaSeries, SIGNAL(pointLabelsFormatChanged(QString)),
+ this, SLOT(handleUpdated()));
+ QObject::connect(areaSeries, SIGNAL(pointLabelsVisibilityChanged(bool)),
+ this, SLOT(handleUpdated()));
+ QObject::connect(areaSeries, SIGNAL(pointLabelsFontChanged(QFont)),
+ this, SLOT(handleUpdated()));
+ QObject::connect(areaSeries, SIGNAL(pointLabelsColorChanged(QColor)),
+ this, SLOT(handleUpdated()));
+
+ handleUpdated();
+}
+
+AreaChartItem::~AreaChartItem()
+{
+ delete m_upper;
+ delete m_lower;
+}
+
+void AreaChartItem::setPresenter(ChartPresenter *presenter)
+{
+ if (m_upper)
+ m_upper->setPresenter(presenter);
+ if (m_lower) {
+ m_lower->setPresenter(presenter);
+ }
+ ChartItem::setPresenter(presenter);
+}
+
+QRectF AreaChartItem::boundingRect() const
+{
+ return m_rect;
+}
+
+QPainterPath AreaChartItem::shape() const
+{
+ return m_path;
+}
+
+void AreaChartItem::updatePath()
+{
+ QPainterPath path;
+ QRectF rect(QPointF(0,0),domain()->size());
+
+ path = m_upper->path();
+
+ if (m_lower) {
+ // Note: Polarcharts always draw area correctly only when both series have equal width or are
+ // fully displayed. If one series is partally off-chart, the connecting line between
+ // the series does not attach to the end of the partially hidden series but to the point
+ // where it intersects the axis line. The problem is especially noticeable when one of the series
+ // is entirely off-chart, in which case the connecting line connects two ends of the
+ // visible series.
+ // This happens because we get the paths from linechart, which omits off-chart segments.
+ // To properly fix, linechart would need to provide true full path, in right, left, and the rest
+ // portions to enable proper clipping. However, combining those to single visually unified area
+ // would be a nightmare, since they would have to be painted separately.
+ path.connectPath(m_lower->path().toReversed());
+ } else {
+ QPointF first = path.pointAtPercent(0);
+ QPointF last = path.pointAtPercent(1);
+ if (presenter()->chartType() == QChart::ChartTypeCartesian) {
+ path.lineTo(last.x(), rect.bottom());
+ path.lineTo(first.x(), rect.bottom());
+ } else { // polar
+ path.lineTo(rect.center());
+ }
+ }
+ path.closeSubpath();
+
+ // Only zoom in if the bounding rect of the path fits inside int limits. QWidget::update() uses
+ // a region that has to be compatible with QRect.
+ if (path.boundingRect().height() <= INT_MAX
+ && path.boundingRect().width() <= INT_MAX) {
+ prepareGeometryChange();
+ m_path = path;
+ m_rect = path.boundingRect();
+ update();
+ }
+}
+
+void AreaChartItem::handleUpdated()
+{
+ setVisible(m_series->isVisible());
+ m_pointsVisible = m_series->pointsVisible();
+ m_linePen = m_series->pen();
+ m_brush = m_series->brush();
+ m_pointPen = m_series->pen();
+ m_pointPen.setWidthF(2 * m_pointPen.width());
+ setOpacity(m_series->opacity());
+ m_pointLabelsFormat = m_series->pointLabelsFormat();
+ m_pointLabelsVisible = m_series->pointLabelsVisible();
+ m_pointLabelsFont = m_series->pointLabelsFont();
+ m_pointLabelsColor = m_series->pointLabelsColor();
+ update();
+}
+
+void AreaChartItem::handleDomainUpdated()
+{
+ if (m_upper) {
+ AbstractDomain* d = m_upper->domain();
+ d->setSize(domain()->size());
+ d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY());
+ m_upper->handleDomainUpdated();
+ }
+
+ if (m_lower) {
+ AbstractDomain* d = m_lower->domain();
+ d->setSize(domain()->size());
+ d->setRange(domain()->minX(),domain()->maxX(),domain()->minY(),domain()->maxY());
+ m_lower->handleDomainUpdated();
+ }
+}
+
+void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(widget)
+ Q_UNUSED(option)
+ painter->save();
+ painter->setPen(m_linePen);
+ painter->setBrush(m_brush);
+ QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
+ if (presenter()->chartType() == QChart::ChartTypePolar)
+ painter->setClipRegion(QRegion(clipRect.toRect(), QRegion::Ellipse));
+ else
+ painter->setClipRect(clipRect);
+ painter->drawPath(m_path);
+ if (m_pointsVisible) {
+ painter->setPen(m_pointPen);
+ painter->drawPoints(m_upper->geometryPoints());
+ if (m_lower)
+ painter->drawPoints(m_lower->geometryPoints());
+ }
+
+ // Draw series point label
+ if (m_pointLabelsVisible) {
+ static const QString xPointTag(QLatin1String("@xPoint"));
+ static const QString yPointTag(QLatin1String("@yPoint"));
+ const int labelOffset = 2;
+
+ painter->setFont(m_pointLabelsFont);
+ painter->setPen(QPen(m_pointLabelsColor));
+ QFontMetrics fm(painter->font());
+
+ QString pointLabel = m_pointLabelsFormat;
+
+ if (m_series->upperSeries()) {
+ for (int i(0); i < m_series->upperSeries()->count(); i++) {
+ pointLabel.replace(xPointTag,
+ presenter()->numberToString(m_series->upperSeries()->at(i).x()));
+ pointLabel.replace(yPointTag,
+ presenter()->numberToString(m_series->upperSeries()->at(i).y()));
+
+ // Position text in relation to the point
+ int pointLabelWidth = fm.width(pointLabel);
+ QPointF position(m_upper->geometryPoints().at(i));
+ position.setX(position.x() - pointLabelWidth / 2);
+ position.setY(position.y() - m_series->upperSeries()->pen().width() / 2 - labelOffset);
+
+ painter->drawText(position, pointLabel);
+ }
+ }
+
+ if (m_series->lowerSeries()) {
+ for (int i(0); i < m_series->lowerSeries()->count(); i++) {
+ pointLabel.replace(xPointTag,
+ presenter()->numberToString(m_series->lowerSeries()->at(i).x()));
+ pointLabel.replace(yPointTag,
+ presenter()->numberToString(m_series->lowerSeries()->at(i).y()));
+
+ // Position text in relation to the point
+ int pointLabelWidth = fm.width(pointLabel);
+ QPointF position(m_lower->geometryPoints().at(i));
+ position.setX(position.x() - pointLabelWidth / 2);
+ position.setY(position.y() - m_series->lowerSeries()->pen().width() / 2 - labelOffset);
+
+ painter->drawText(position, pointLabel);
+ }
+ }
+ }
+
+ painter->restore();
+}
+
+void AreaChartItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ emit clicked(m_upper->domain()->calculateDomainPoint(event->pos()));
+ ChartItem::mousePressEvent(event);
+}
+
+void AreaChartItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ emit hovered(domain()->calculateDomainPoint(event->pos()), true);
+ event->accept();
+// QGraphicsItem::hoverEnterEvent(event);
+}
+
+void AreaChartItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ emit hovered(domain()->calculateDomainPoint(event->pos()), false);
+ event->accept();
+// QGraphicsItem::hoverEnterEvent(event);
+}
+
+#include "moc_areachartitem_p.cpp"
+
+QT_CHARTS_END_NAMESPACE