| 1 | // Copyright (C) 2021 The Qt Company Ltd. | 
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only | 
| 3 |  | 
| 4 | #include <QtCharts/QScatterSeries> | 
| 5 | #include <private/qscatterseries_p.h> | 
| 6 | #include <private/scatterchartitem_p.h> | 
| 7 | #include <private/chartdataset_p.h> | 
| 8 | #include <private/charttheme_p.h> | 
| 9 | #include <private/scatteranimation_p.h> | 
| 10 | #include <private/qchart_p.h> | 
| 11 |  | 
| 12 | /*! | 
| 13 |     \class QScatterSeries | 
| 14 |     \inmodule QtCharts | 
| 15 |     \brief The QScatterSeries class presents data in scatter charts. | 
| 16 |  | 
| 17 |     The scatter data is displayed as a collection of points on the chart. For | 
| 18 |     each point, two values are specified that determine its position on the | 
| 19 |     horizontal axis and the vertical axis. | 
| 20 |  | 
| 21 |     \image examples_scatterchart.png | 
| 22 |  | 
| 23 |     The following code snippet illustrates how to create a basic scatter chart: | 
| 24 |     \code | 
| 25 |     QScatterSeries* series = new QScatterSeries(); | 
| 26 |     series->append(0, 6); | 
| 27 |     series->append(2, 4); | 
| 28 |     ... | 
| 29 |     chart->addSeries(series); | 
| 30 |     \endcode | 
| 31 |  | 
| 32 |     For more information, see \l{Charts with Widgets Gallery} and | 
| 33 |     \l {Creating Scatter Charts}. | 
| 34 | */ | 
| 35 | /*! | 
| 36 |     \qmltype ScatterSeries | 
| 37 |     \nativetype QScatterSeries | 
| 38 |     \inqmlmodule QtCharts | 
| 39 |  | 
| 40 |     \inherits XYSeries | 
| 41 |  | 
| 42 |     \brief The ScatterSeries type presents data in scatter charts. | 
| 43 |  | 
| 44 |     The scatter data is displayed as a collection of points on the chart. For | 
| 45 |     each point, two values are specified that determine its position on the | 
| 46 |     horizontal axis and the vertical axis. | 
| 47 |  | 
| 48 |     \image examples_qmlchart5.png | 
| 49 |  | 
| 50 |     The following QML code shows how to create a chart with two simple scatter | 
| 51 |     series: | 
| 52 |     \snippet qmlchartsgallery/qml/ScatterSeries.qml 1 | 
| 53 |  | 
| 54 |     For more information, see \l{Charts with QML Gallery}. | 
| 55 | */ | 
| 56 |  | 
| 57 | /*! | 
| 58 |     \enum QScatterSeries::MarkerShape | 
| 59 |  | 
| 60 |     This enum value describes the shape used when rendering marker items. | 
| 61 |  | 
| 62 |     \value MarkerShapeCircle | 
| 63 |            The marker is a circle. This is the default value. | 
| 64 |     \value MarkerShapeRectangle | 
| 65 |            The marker is a rectangle. | 
| 66 |     \value MarkerShapeRotatedRectangle | 
| 67 |            The marker is a rotated rectangle. | 
| 68 |     \value MarkerShapeTriangle | 
| 69 |            The marker is a triangle. | 
| 70 |     \value MarkerShapeStar | 
| 71 |            The marker is a star. | 
| 72 |     \value MarkerShapePentagon | 
| 73 |            The marker is a pentagon. | 
| 74 | */ | 
| 75 |  | 
| 76 | /*! | 
| 77 |     \property QScatterSeries::brush | 
| 78 |     \brief The brush used to draw the scatter series markers. | 
| 79 |  | 
| 80 |     The brush can be an image that can be created using QPainterPath, | 
| 81 |     for example. | 
| 82 | */ | 
| 83 |  | 
| 84 | /*! | 
| 85 |     \qmlproperty brush ScatterSeries::brush | 
| 86 |     The brush used to draw the scatter series markers. | 
| 87 | */ | 
| 88 |  | 
| 89 | /*! | 
| 90 |     \property QScatterSeries::color | 
| 91 |     \brief The color used to fill the series markers. | 
| 92 |  | 
| 93 |     This is a convenience property for modifying the color of the brush. | 
| 94 |     \sa QScatterSeries::brush() | 
| 95 | */ | 
| 96 |  | 
| 97 | /*! | 
| 98 |     \property QScatterSeries::borderColor | 
| 99 |     \brief The color used to draw the marker borders. | 
| 100 |  | 
| 101 |     This is a convenience property for modifying the color of the pen. | 
| 102 |     \sa QScatterSeries::pen() | 
| 103 | */ | 
| 104 |  | 
| 105 | /*! | 
| 106 |     \qmlproperty int ScatterSeries::count | 
| 107 |     The number of data points in the series. | 
| 108 | */ | 
| 109 |  | 
| 110 | /*! | 
| 111 |     \qmlproperty color ScatterSeries::borderColor | 
| 112 |     The color used to draw the marker borders. | 
| 113 | */ | 
| 114 |  | 
| 115 | /*! | 
| 116 |     \qmlproperty real ScatterSeries::borderWidth | 
| 117 |     The width of the border line. By default, the width is 2.0. | 
| 118 | */ | 
| 119 |  | 
| 120 | /*! | 
| 121 |     \property QScatterSeries::markerShape | 
| 122 |     \brief The shape of the marker used to render the points in the series. | 
| 123 |  | 
| 124 |     The default shape is MarkerShapeCircle. | 
| 125 |  | 
| 126 |     \sa MarkerShape | 
| 127 | */ | 
| 128 | /*! | 
| 129 |     \qmlproperty enumeration ScatterSeries::markerShape | 
| 130 |  | 
| 131 |     The shape used when rendering marker items: | 
| 132 |  | 
| 133 |     \value ScatterSeries.MarkerShapeCircle | 
| 134 |            The marker is a circle. This is the default value. | 
| 135 |     \value ScatterSeries.MarkerShapeRectangle | 
| 136 |            The marker is a rectangle. | 
| 137 | */ | 
| 138 |  | 
| 139 | /*! | 
| 140 |     \property QScatterSeries::markerSize | 
| 141 |     \brief The size of the marker used to render the points in the series. | 
| 142 |  | 
| 143 |     \sa QXYSeries::setMarkerSize | 
| 144 | */ | 
| 145 | /*! | 
| 146 |     \qmlproperty real ScatterSeries::markerSize | 
| 147 |     The size of the marker used to render the points in the series. | 
| 148 | */ | 
| 149 |  | 
| 150 | /*! | 
| 151 |     \qmlproperty string ScatterSeries::brushFilename | 
| 152 |     The name of the file used as a brush for the series. | 
| 153 | */ | 
| 154 |  | 
| 155 | /*! | 
| 156 |     \fn void QScatterSeries::colorChanged(QColor color) | 
| 157 |     This signal is emitted when the fill (brush) color changes to \a color. | 
| 158 | */ | 
| 159 |  | 
| 160 | /*! | 
| 161 |     \fn void QScatterSeries::borderColorChanged(QColor color) | 
| 162 |     This signal is emitted when the line (pen) color changes to \a color. | 
| 163 | */ | 
| 164 |  | 
| 165 | /*! | 
| 166 |     \fn void QScatterSeries::markerShapeChanged(MarkerShape shape) | 
| 167 |     This signal is emitted when the marker shape changes to \a shape. | 
| 168 | */ | 
| 169 |  | 
| 170 | /*! | 
| 171 |     \fn void QScatterSeries::markerSizeChanged(qreal size) | 
| 172 |     This signal is emitted when the marker size changes to \a size. | 
| 173 | */ | 
| 174 |  | 
| 175 | QT_BEGIN_NAMESPACE | 
| 176 |  | 
| 177 | /*! | 
| 178 |     Constructs a series object that is a child of \a parent. | 
| 179 | */ | 
| 180 | QScatterSeries::QScatterSeries(QObject *parent) | 
| 181 |     : QXYSeries(*new QScatterSeriesPrivate(this), parent) | 
| 182 | { | 
| 183 |     setPointsVisible(true); | 
| 184 |  | 
| 185 |     // Emit QScatterSeries' markerSizeChanged signal as it's not the same as | 
| 186 |     // QXYSeries' markerSizeChanged | 
| 187 |     connect(sender: this, signal: &QXYSeries::markerSizeChanged, context: this, slot: &QScatterSeries::markerSizeChanged); | 
| 188 | } | 
| 189 |  | 
| 190 | /*! | 
| 191 |     Deletes the scatter series. | 
| 192 |  | 
| 193 |     \note Adding the series to QChart transfers the ownership to the chart. | 
| 194 | */ | 
| 195 | QScatterSeries::~QScatterSeries() | 
| 196 | { | 
| 197 |     Q_D(QScatterSeries); | 
| 198 |     if (d->m_chart) | 
| 199 |         d->m_chart->removeSeries(series: this); | 
| 200 | } | 
| 201 |  | 
| 202 | /*! | 
| 203 |     \reimp | 
| 204 | */ | 
| 205 | QAbstractSeries::SeriesType QScatterSeries::type() const | 
| 206 | { | 
| 207 |     return QAbstractSeries::SeriesTypeScatter; | 
| 208 | } | 
| 209 |  | 
| 210 | /*! | 
| 211 |     \reimp | 
| 212 | */ | 
| 213 | void QScatterSeries::setPen(const QPen &pen) | 
| 214 | { | 
| 215 |     Q_D(QXYSeries); | 
| 216 |     if (d->m_pen != pen) { | 
| 217 |         bool emitColorChanged = d->m_pen.color() != pen.color(); | 
| 218 |         d->m_pen = pen; | 
| 219 |         emit d->seriesUpdated(); | 
| 220 |         if (emitColorChanged) | 
| 221 |             emit borderColorChanged(color: pen.color()); | 
| 222 |     } | 
| 223 | } | 
| 224 |  | 
| 225 | /*! | 
| 226 |     \reimp | 
| 227 | */ | 
| 228 | void QScatterSeries::setBrush(const QBrush &brush) | 
| 229 | { | 
| 230 |     Q_D(QScatterSeries); | 
| 231 |     if (d->m_brush != brush) { | 
| 232 |         bool emitColorChanged = d->m_brush.color() != brush.color(); | 
| 233 |         d->m_brush = brush; | 
| 234 |         emit d->seriesUpdated(); | 
| 235 |         if (emitColorChanged) | 
| 236 |             emit colorChanged(color: brush.color()); | 
| 237 |     } | 
| 238 | } | 
| 239 |  | 
| 240 | QBrush QScatterSeries::brush() const | 
| 241 | { | 
| 242 |     Q_D(const QScatterSeries); | 
| 243 |     if (d->m_brush == QChartPrivate::defaultBrush()) | 
| 244 |         return QBrush(); | 
| 245 |     else | 
| 246 |         return d->m_brush; | 
| 247 | } | 
| 248 |  | 
| 249 | void QScatterSeries::setColor(const QColor &color) | 
| 250 | { | 
| 251 |     QBrush b = brush(); | 
| 252 |     if (b == QChartPrivate::defaultBrush()) | 
| 253 |         b = QBrush(); | 
| 254 |     if (b == QBrush()) | 
| 255 |         b.setStyle(Qt::SolidPattern); | 
| 256 |     b.setColor(color); | 
| 257 |     setBrush(b); | 
| 258 | } | 
| 259 |  | 
| 260 | QColor QScatterSeries::color() const | 
| 261 | { | 
| 262 |     return brush().color(); | 
| 263 | } | 
| 264 |  | 
| 265 | void QScatterSeries::setBorderColor(const QColor &color) | 
| 266 | { | 
| 267 |     QPen p = pen(); | 
| 268 |     if (p == QChartPrivate::defaultPen()) | 
| 269 |         p = QPen(); | 
| 270 |     p.setColor(color); | 
| 271 |     setPen(p); | 
| 272 | } | 
| 273 |  | 
| 274 | QColor QScatterSeries::borderColor() const | 
| 275 | { | 
| 276 |     return pen().color(); | 
| 277 | } | 
| 278 |  | 
| 279 | QScatterSeries::MarkerShape QScatterSeries::markerShape() const | 
| 280 | { | 
| 281 |     Q_D(const QScatterSeries); | 
| 282 |     return d->m_shape; | 
| 283 | } | 
| 284 |  | 
| 285 | void QScatterSeries::setMarkerShape(MarkerShape shape) | 
| 286 | { | 
| 287 |     Q_D(QScatterSeries); | 
| 288 |     if (d->m_shape != shape) { | 
| 289 |         d->m_shape = shape; | 
| 290 |         emit d->seriesUpdated(); | 
| 291 |         emit markerShapeChanged(shape); | 
| 292 |     } | 
| 293 | } | 
| 294 |  | 
| 295 | qreal QScatterSeries::markerSize() const | 
| 296 | { | 
| 297 |     // markerSize has moved to QXYSeries, but this method needs to remain for API compatibility. | 
| 298 |     return QXYSeries::markerSize(); | 
| 299 | } | 
| 300 | void QScatterSeries::setMarkerSize(qreal size) | 
| 301 | { | 
| 302 |     // markerSize has moved to QXYSeries, but this method needs to remain for API compatibility. | 
| 303 |     QXYSeries::setMarkerSize(size); | 
| 304 | } | 
| 305 |  | 
| 306 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | 
| 307 |  | 
| 308 | QScatterSeriesPrivate::QScatterSeriesPrivate(QScatterSeries *q) | 
| 309 |     : QXYSeriesPrivate(q), | 
| 310 |       m_shape(QScatterSeries::MarkerShapeCircle) | 
| 311 | { | 
| 312 | } | 
| 313 |  | 
| 314 | void QScatterSeriesPrivate::initializeGraphics(QGraphicsItem* parent) | 
| 315 | { | 
| 316 |     Q_Q(QScatterSeries); | 
| 317 |     ScatterChartItem *scatter = new ScatterChartItem(q,parent); | 
| 318 |     m_item.reset(p: scatter); | 
| 319 |     QAbstractSeriesPrivate::initializeGraphics(parent); | 
| 320 | } | 
| 321 |  | 
| 322 | void QScatterSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced) | 
| 323 | { | 
| 324 |     Q_Q(QScatterSeries); | 
| 325 |     const QList<QColor> colors = theme->seriesColors(); | 
| 326 |     const QList<QGradient> gradients = theme->seriesGradients(); | 
| 327 |  | 
| 328 |     if (forced || QChartPrivate::defaultPen() == m_pen) { | 
| 329 |         QPen pen; | 
| 330 |         pen.setColor(ChartThemeManager::colorAt(gradient: gradients.at(i: index % gradients.size()), pos: 0.0)); | 
| 331 |         pen.setWidthF(2); | 
| 332 |         q->setPen(pen); | 
| 333 |     } | 
| 334 |  | 
| 335 |     if (forced || QChartPrivate::defaultBrush() == m_brush) { | 
| 336 |         QBrush brush(colors.at(i: index % colors.size())); | 
| 337 |         q->setBrush(brush); | 
| 338 |     } | 
| 339 |  | 
| 340 |     if (forced || QChartPrivate::defaultPen().color() == m_pointLabelsColor) { | 
| 341 |         QColor color = theme->labelBrush().color(); | 
| 342 |         q->setPointLabelsColor(color); | 
| 343 |     } | 
| 344 | } | 
| 345 |  | 
| 346 | void QScatterSeriesPrivate::initializeAnimations(QChart::AnimationOptions options, int duration, | 
| 347 |                                                  QEasingCurve &curve) | 
| 348 | { | 
| 349 |     ScatterChartItem *item = static_cast<ScatterChartItem *>(m_item.get()); | 
| 350 |     Q_ASSERT(item); | 
| 351 |  | 
| 352 |     if (item->animation()) | 
| 353 |         item->animation()->stopAndDestroyLater(); | 
| 354 |  | 
| 355 |     if (options.testFlag(flag: QChart::SeriesAnimations)) | 
| 356 |         item->setAnimation(new ScatterAnimation(item, duration, curve)); | 
| 357 |     else | 
| 358 |         item->setAnimation(0); | 
| 359 |  | 
| 360 |     QAbstractSeriesPrivate::initializeAnimations(options, duration, curve); | 
| 361 | } | 
| 362 |  | 
| 363 | QT_END_NAMESPACE | 
| 364 |  | 
| 365 | #include "moc_qscatterseries.cpp" | 
| 366 |  |