| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2017 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the Qt Charts module of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 or (at your option) any later version | 
| 20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by | 
| 21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 | 
| 22 | ** included in the packaging of this file. Please review the following | 
| 23 | ** information to ensure the GNU General Public License requirements will | 
| 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 25 | ** | 
| 26 | ** $QT_END_LICENSE$ | 
| 27 | ** | 
| 28 | ****************************************************************************/ | 
| 29 |  | 
| 30 | #include <QtCharts/QXYSeries> | 
| 31 | #include <private/qxyseries_p.h> | 
| 32 | #include <private/abstractdomain_p.h> | 
| 33 | #include <QtCharts/QValueAxis> | 
| 34 | #include <private/xychart_p.h> | 
| 35 | #include <QtCharts/QXYLegendMarker> | 
| 36 | #include <private/charthelpers_p.h> | 
| 37 | #include <private/qchart_p.h> | 
| 38 | #include <QtGui/QPainter> | 
| 39 |  | 
| 40 | QT_CHARTS_BEGIN_NAMESPACE | 
| 41 |  | 
| 42 | /*! | 
| 43 |     \class QXYSeries | 
| 44 |     \inmodule QtCharts | 
| 45 |     \brief The QXYSeries class is a base class for line, spline, and scatter | 
| 46 |     series. | 
| 47 | */ | 
| 48 | /*! | 
| 49 |     \qmltype XYSeries | 
| 50 |     \instantiates QXYSeries | 
| 51 |     \inqmlmodule QtCharts | 
| 52 |  | 
| 53 |     \inherits AbstractSeries | 
| 54 |  | 
| 55 |     \brief A base type for line, spline, and scatter series. | 
| 56 | */ | 
| 57 |  | 
| 58 | /*! | 
| 59 |     \qmlproperty AbstractAxis XYSeries::axisX | 
| 60 |     The x-axis used for the series. If you leave both axisX and axisXTop | 
| 61 |     undefined, a value axis is created for the series. | 
| 62 |     \sa axisXTop, ValueAxis | 
| 63 | */ | 
| 64 |  | 
| 65 | /*! | 
| 66 |     \qmlproperty AbstractAxis XYSeries::axisY | 
| 67 |     The y-axis used for the series. If you leave both axisY and axisYRight | 
| 68 |     undefined, a value axis is created for the series. | 
| 69 |     \sa axisYRight, ValueAxis | 
| 70 | */ | 
| 71 |  | 
| 72 | /*! | 
| 73 |     \qmlproperty AbstractAxis XYSeries::axisXTop | 
| 74 |     The x-axis used for the series, drawn on top of the chart view. | 
| 75 |  | 
| 76 |     \note You can only provide either axisX or axisXTop, not both. | 
| 77 |     \sa axisX | 
| 78 | */ | 
| 79 |  | 
| 80 | /*! | 
| 81 |     \qmlproperty AbstractAxis XYSeries::axisYRight | 
| 82 |     The y-axis used for the series, drawn to the right on the chart view. | 
| 83 |  | 
| 84 |     \note You can only provide either axisY or axisYRight, not both. | 
| 85 |     \sa axisY | 
| 86 | */ | 
| 87 |  | 
| 88 | /*! | 
| 89 |     \qmlproperty AbstractAxis XYSeries::axisAngular | 
| 90 |     The angular axis used for the series, drawn around the polar chart view. | 
| 91 |     \sa axisX | 
| 92 | */ | 
| 93 |  | 
| 94 | /*! | 
| 95 |     \qmlproperty AbstractAxis XYSeries::axisRadial | 
| 96 |     The radial axis used for the series, drawn inside the polar chart view. | 
| 97 |     \sa axisY | 
| 98 | */ | 
| 99 |  | 
| 100 | /*! | 
| 101 |     \property QXYSeries::pointsVisible | 
| 102 |     \brief Whether the data points are visible and should be drawn. | 
| 103 | */ | 
| 104 | /*! | 
| 105 |     \qmlproperty bool XYSeries::pointsVisible | 
| 106 |     Whether the data points are visible and should be drawn. | 
| 107 | */ | 
| 108 |  | 
| 109 | /*! | 
| 110 |    \fn QPen QXYSeries::pen() const | 
| 111 |    Returns the pen used to draw the outline of the data points for the series. | 
| 112 |     \sa setPen() | 
| 113 | */ | 
| 114 |  | 
| 115 | /*! | 
| 116 |    \fn QBrush QXYSeries::brush() const | 
| 117 |    Returns the brush used to fill the data points for the series. | 
| 118 |     \sa setBrush() | 
| 119 | */ | 
| 120 |  | 
| 121 | /*! | 
| 122 |     \property QXYSeries::color | 
| 123 |     \brief The color of the series. | 
| 124 |  | 
| 125 |     This is the line (pen) color in case of QLineSeries or QSplineSeries and the | 
| 126 |     fill (brush) color in case of QScatterSeries or QAreaSeries. | 
| 127 |     \sa pen(), brush() | 
| 128 | */ | 
| 129 | /*! | 
| 130 |     \qmlproperty color XYSeries::color | 
| 131 |     The color of the series. This is the line (pen) color in case of LineSeries | 
| 132 |     or SplineSeries and the fill (brush) color in case of ScatterSeries or | 
| 133 |     AreaSeries. | 
| 134 | */ | 
| 135 |  | 
| 136 | /*! | 
| 137 |     \property QXYSeries::pointLabelsFormat | 
| 138 |     \brief The format used for showing labels with data points. | 
| 139 |  | 
| 140 |     QXYSeries supports the following format tags: | 
| 141 |     \table | 
| 142 |       \row | 
| 143 |         \li @xPoint      \li The x-coordinate of the data point. | 
| 144 |       \row | 
| 145 |         \li @yPoint      \li The y-coordinate of the data point. | 
| 146 |     \endtable | 
| 147 |  | 
| 148 |     For example, the following usage of the format tags would produce labels | 
| 149 |     that display the data point shown inside brackets separated by a comma | 
| 150 |     (x, y): | 
| 151 |  | 
| 152 |     \code | 
| 153 |     series->setPointLabelsFormat("(@xPoint, @yPoint)"); | 
| 154 |     \endcode | 
| 155 |  | 
| 156 |     By default, the labels' format is set to \c {@xPoint, @yPoint}. The labels | 
| 157 |     are shown on the plot area, and the labels on the edge of the plot area are | 
| 158 |     cut. If the points are close to each other, the labels may overlap. | 
| 159 |  | 
| 160 |     \sa pointLabelsVisible, pointLabelsFont, pointLabelsColor | 
| 161 | */ | 
| 162 | /*! | 
| 163 |     \qmlproperty string XYSeries::pointLabelsFormat | 
| 164 |     The format used for showing labels with data points. | 
| 165 |  | 
| 166 |     \sa pointLabelsVisible, pointLabelsFont, pointLabelsColor | 
| 167 | */ | 
| 168 | /*! | 
| 169 |     \fn void QXYSeries::pointLabelsFormatChanged(const QString &format) | 
| 170 |     This signal is emitted when the format of data point labels changes to | 
| 171 |     \a format. | 
| 172 | */ | 
| 173 |  | 
| 174 | /*! | 
| 175 |     \property QXYSeries::pointLabelsVisible | 
| 176 |     \brief The visibility of data point labels. | 
| 177 |  | 
| 178 |     This property is \c false by default. | 
| 179 |  | 
| 180 |     \sa pointLabelsFormat, pointLabelsClipping | 
| 181 | */ | 
| 182 | /*! | 
| 183 |     \qmlproperty bool XYSeries::pointLabelsVisible | 
| 184 |     The visibility of data point labels. This property is \c false by default. | 
| 185 |  | 
| 186 |     \sa pointLabelsFormat, pointLabelsClipping | 
| 187 | */ | 
| 188 | /*! | 
| 189 |     \fn void QXYSeries::pointLabelsVisibilityChanged(bool visible) | 
| 190 |     This signal is emitted when the visibility of the data point labels | 
| 191 |     changes to \a visible. | 
| 192 | */ | 
| 193 |  | 
| 194 | /*! | 
| 195 |     \property QXYSeries::pointLabelsFont | 
| 196 |     \brief The font used for data point labels. | 
| 197 |  | 
| 198 |     \sa pointLabelsFormat | 
| 199 | */ | 
| 200 | /*! | 
| 201 |     \qmlproperty font XYSeries::pointLabelsFont | 
| 202 |     The font used for data point labels. | 
| 203 |  | 
| 204 |     \sa pointLabelsFormat | 
| 205 | */ | 
| 206 | /*! | 
| 207 |     \fn void QXYSeries::pointLabelsFontChanged(const QFont &font); | 
| 208 |     This signal is emitted when the font used for data point labels changes to | 
| 209 |     \a font. | 
| 210 | */ | 
| 211 |  | 
| 212 | /*! | 
| 213 |     \property QXYSeries::pointLabelsColor | 
| 214 |     \brief The color used for data point labels. By default, the color is the color of the brush | 
| 215 |     defined in theme for labels. | 
| 216 |  | 
| 217 |     \sa pointLabelsFormat | 
| 218 | */ | 
| 219 | /*! | 
| 220 |     \qmlproperty font XYSeries::pointLabelsColor | 
| 221 |     The color used for data point labels. By default, the color is the color of the brush | 
| 222 |     defined in theme for labels. | 
| 223 |  | 
| 224 |     \sa pointLabelsFormat | 
| 225 | */ | 
| 226 | /*! | 
| 227 |     \fn void QXYSeries::pointLabelsColorChanged(const QColor &color); | 
| 228 |     This signal is emitted when the color used for data point labels changes to | 
| 229 |     \a color. | 
| 230 | */ | 
| 231 |  | 
| 232 | /*! | 
| 233 |     \property QXYSeries::pointLabelsClipping | 
| 234 |     \brief The clipping for data point labels. | 
| 235 |  | 
| 236 |     This property is \c true by default. The labels on the edge of the plot area | 
| 237 |     are cut when clipping is enabled. | 
| 238 |  | 
| 239 |     \sa pointLabelsVisible | 
| 240 | */ | 
| 241 | /*! | 
| 242 |     \qmlproperty bool XYSeries::pointLabelsClipping | 
| 243 |     The clipping for data point labels. This property is \c true by default. The | 
| 244 |     labels on the edge of the plot area are cut when clipping is enabled. | 
| 245 |  | 
| 246 |     \sa pointLabelsVisible | 
| 247 | */ | 
| 248 | /*! | 
| 249 |     \fn void QXYSeries::pointLabelsClippingChanged(bool clipping) | 
| 250 |     This signal is emitted when the clipping of the data point labels changes to | 
| 251 |     \a clipping. | 
| 252 | */ | 
| 253 |  | 
| 254 | /*! | 
| 255 |     \fn void QXYSeries::clicked(const QPointF& point) | 
| 256 |     This signal is emitted when the user triggers a mouse event by | 
| 257 |     clicking the point \a point in the chart. | 
| 258 |  | 
| 259 |     \sa pressed(), released(), doubleClicked() | 
| 260 | */ | 
| 261 | /*! | 
| 262 |     \qmlsignal XYSeries::clicked(point point) | 
| 263 |     This signal is emitted when the user triggers a mouse event by clicking the | 
| 264 |     point \a point in the chart. For example: | 
| 265 |     \code | 
| 266 |     LineSeries { | 
| 267 |         XYPoint { x: 0; y: 0 } | 
| 268 |         XYPoint { x: 1.1; y: 2.1 } | 
| 269 |         onClicked: console.log("onClicked: " + point.x + ", " + point.y); | 
| 270 |     } | 
| 271 |     \endcode | 
| 272 |  | 
| 273 |     The corresponding signal handler is \c onClicked(). | 
| 274 |  | 
| 275 |     \sa pressed(), released(), doubleClicked() | 
| 276 | */ | 
| 277 |  | 
| 278 | /*! | 
| 279 |     \fn void QXYSeries::hovered(const QPointF &point, bool state) | 
| 280 |     This signal is emitted when a mouse is hovered over the point \a point in | 
| 281 |     the chart. When the mouse moves over the point, \a state turns \c true, | 
| 282 |     and when the mouse moves away again, it turns \c false. | 
| 283 | */ | 
| 284 | /*! | 
| 285 |     \qmlsignal XYSeries::hovered(point point, bool state) | 
| 286 |     This signal is emitted when a mouse is hovered over the point \a point in | 
| 287 |     the chart. When the mouse moves over the point, \a state turns \c true, | 
| 288 |     and when the mouse moves away again, it turns \c false. | 
| 289 |  | 
| 290 |     The corresponding signal handler is \c onHovered(). | 
| 291 | */ | 
| 292 |  | 
| 293 | /*! | 
| 294 |     \fn void QXYSeries::pressed(const QPointF& point) | 
| 295 |     This signal is emitted when the user presses the data point \a point in the | 
| 296 |     chart and holds down the mouse button. | 
| 297 |  | 
| 298 |     \sa clicked(), released(), doubleClicked() | 
| 299 | */ | 
| 300 | /*! | 
| 301 |     \qmlsignal XYSeries::pressed(point point) | 
| 302 |     This signal is emitted when the user presses the data point \a point in the | 
| 303 |     chart and holds down the mouse button. For example: | 
| 304 |     \code | 
| 305 |     LineSeries { | 
| 306 |         XYPoint { x: 0; y: 0 } | 
| 307 |         XYPoint { x: 1.1; y: 2.1 } | 
| 308 |         onPressed: console.log("onPressed: " + point.x + ", " + point.y); | 
| 309 |     } | 
| 310 |     \endcode | 
| 311 |  | 
| 312 |     The corresponding signal handler is \c onPressed(). | 
| 313 |  | 
| 314 |     \sa clicked(), released(), doubleClicked() | 
| 315 | */ | 
| 316 |  | 
| 317 | /*! | 
| 318 |     \fn void QXYSeries::released(const QPointF& point) | 
| 319 |     This signal is emitted when the user releases the mouse press on the data | 
| 320 |     point specified by \a point. | 
| 321 |     \sa pressed(), clicked(), doubleClicked() | 
| 322 | */ | 
| 323 | /*! | 
| 324 |     \qmlsignal XYSeries::released(point point) | 
| 325 |     This signal is emitted when the user releases the mouse press on the data | 
| 326 |     point specified by \a point. | 
| 327 |     For example: | 
| 328 |     \code | 
| 329 |     LineSeries { | 
| 330 |         XYPoint { x: 0; y: 0 } | 
| 331 |         XYPoint { x: 1.1; y: 2.1 } | 
| 332 |         onReleased: console.log("onReleased: " + point.x + ", " + point.y); | 
| 333 |     } | 
| 334 |     \endcode | 
| 335 |  | 
| 336 |     The corresponding signal handler is \c onReleased(). | 
| 337 |  | 
| 338 |     \sa pressed(), clicked(), doubleClicked() | 
| 339 | */ | 
| 340 |  | 
| 341 | /*! | 
| 342 |     \fn void QXYSeries::doubleClicked(const QPointF& point) | 
| 343 |     This signal is emitted when the user double-clicks the data point \a point | 
| 344 |     in the chart. The \a point is the point where the first press was triggered. | 
| 345 |     \sa pressed(), released(), clicked() | 
| 346 | */ | 
| 347 | /*! | 
| 348 |     \qmlsignal XYSeries::doubleClicked(point point) | 
| 349 |     This signal is emitted when the user double-clicks the data point \a point | 
| 350 |     in the chart. The \a point is the point where the first press was triggered. | 
| 351 |     For example: | 
| 352 |     \code | 
| 353 |     LineSeries { | 
| 354 |         XYPoint { x: 0; y: 0 } | 
| 355 |         XYPoint { x: 1.1; y: 2.1 } | 
| 356 |         onDoubleClicked: console.log("onDoubleClicked: " + point.x + ", " + point.y); | 
| 357 |     } | 
| 358 |     \endcode | 
| 359 |  | 
| 360 |     The corresponding signal handler is \c onDoubleClicked(). | 
| 361 |  | 
| 362 |     \sa pressed(), released(), clicked() | 
| 363 | */ | 
| 364 |  | 
| 365 | /*! | 
| 366 |     \fn void QXYSeries::pointReplaced(int index) | 
| 367 |     This signal is emitted when a point is replaced at the position specified by | 
| 368 |     \a index. | 
| 369 |     \sa replace() | 
| 370 | */ | 
| 371 | /*! | 
| 372 |     \qmlsignal XYSeries::pointReplaced(int index) | 
| 373 |     This signal is emitted when a point is replaced at the position specified by | 
| 374 |     \a index. | 
| 375 |  | 
| 376 |     The corresponding signal handler is \c onPointReplaced(). | 
| 377 | */ | 
| 378 |  | 
| 379 | /*! | 
| 380 |     \fn void QXYSeries::pointsReplaced() | 
| 381 |     This signal is emitted when all points are replaced with other points. | 
| 382 |     \sa replace() | 
| 383 | */ | 
| 384 | /*! | 
| 385 |     \qmlsignal XYSeries::pointsReplaced() | 
| 386 |     This signal is emitted when all points are replaced with other points. | 
| 387 |  | 
| 388 |     The corresponding signal handler is \c onPointsReplaced(). | 
| 389 | */ | 
| 390 |  | 
| 391 | /*! | 
| 392 |     \fn void QXYSeries::pointAdded(int index) | 
| 393 |     This signal is emitted when a point is added at the position specified by | 
| 394 |     \a index. | 
| 395 |     \sa append(), insert() | 
| 396 | */ | 
| 397 | /*! | 
| 398 |     \qmlsignal XYSeries::pointAdded(int index) | 
| 399 |     This signal is emitted when a point is added at the position specified by | 
| 400 |     \a index. | 
| 401 |  | 
| 402 |     The corresponding signal handler is \c onPointAdded(). | 
| 403 | */ | 
| 404 |  | 
| 405 | /*! | 
| 406 |     \fn void QXYSeries::pointRemoved(int index) | 
| 407 |     This signal is emitted when a point is removed from the position specified | 
| 408 |     by \a index. | 
| 409 |     \sa remove() | 
| 410 | */ | 
| 411 |  | 
| 412 | /*! | 
| 413 |     \qmlsignal XYSeries::pointRemoved(int index) | 
| 414 |     This signal is emitted when a point is removed from the position specified | 
| 415 |     by \a index. | 
| 416 |  | 
| 417 |     The corresponding signal handler is \c onPointRemoved(). | 
| 418 | */ | 
| 419 |  | 
| 420 | /*! | 
| 421 |     \fn void QXYSeries::pointsRemoved(int index, int count) | 
| 422 |     This signal is emitted when the number of points specified by \a count | 
| 423 |     is removed starting at the position specified by \a index. | 
| 424 |     \sa removePoints(), clear() | 
| 425 | */ | 
| 426 |  | 
| 427 | /*! | 
| 428 |     \qmlsignal XYSeries::pointsRemoved(int index, int count) | 
| 429 |     This signal is emitted when the number of points specified by \a count | 
| 430 |     is removed starting at the position specified by \a index. | 
| 431 |  | 
| 432 |     The corresponding signal handler is \c onPointRemoved(). | 
| 433 | */ | 
| 434 |  | 
| 435 | /*! | 
| 436 |     \fn void QXYSeries::colorChanged(QColor color) | 
| 437 |     This signal is emitted when the line (pen) color changes to \a color. | 
| 438 | */ | 
| 439 |  | 
| 440 | /*! | 
| 441 |     \fn void QXYSeries::penChanged(const QPen &pen) | 
| 442 |     This signal is emitted when the pen changes to \a pen. | 
| 443 | */ | 
| 444 |  | 
| 445 | /*! | 
| 446 |     \fn void QXYSeriesPrivate::updated() | 
| 447 |     \internal | 
| 448 | */ | 
| 449 |  | 
| 450 | /*! | 
| 451 |     \qmlmethod XYSeries::append(real x, real y) | 
| 452 |     Appends a point with the coordinates \a x and \a y to the series. | 
| 453 | */ | 
| 454 |  | 
| 455 | /*! | 
| 456 |     \qmlmethod XYSeries::replace(real oldX, real oldY, real newX, real newY) | 
| 457 |     Replaces the point with the coordinates \a oldX and \a oldY with the point | 
| 458 |     with the coordinates \a newX and \a newY. Does nothing if the old point does | 
| 459 |     not exist. | 
| 460 | */ | 
| 461 |  | 
| 462 | /*! | 
| 463 |     \qmlmethod XYSeries::remove(real x, real y) | 
| 464 |     Removes the point with the coordinates \a x and \a y from the series. Does | 
| 465 |     nothing if the point does not exist. | 
| 466 | */ | 
| 467 |  | 
| 468 | /*! | 
| 469 |     \qmlmethod XYSeries::remove(int index) | 
| 470 |     Removes the point at the position specified by \a index from the series. | 
| 471 | */ | 
| 472 |  | 
| 473 | /*! | 
| 474 |     \qmlmethod XYSeries::removePoints(int index, int count) | 
| 475 |     Removes the number of points specified by \a count from the series starting | 
| 476 |     at the position specified by \a index. | 
| 477 | */ | 
| 478 |  | 
| 479 | /*! | 
| 480 |     \qmlmethod XYSeries::insert(int index, real x, real y) | 
| 481 |     Inserts a point with the coordinates \a x and \a y to the position specified | 
| 482 |     by \a index in the series. If the index is 0 or less than 0, the point is | 
| 483 |     prepended to the list of points. If the index is equal to or greater than | 
| 484 |     than the number of points in the series, the point is appended to the | 
| 485 |     list of points. | 
| 486 | */ | 
| 487 |  | 
| 488 | /*! | 
| 489 |     \qmlmethod QPointF XYSeries::at(int index) | 
| 490 |     Returns the point at the position specified by \a index. Returns (0, 0) if | 
| 491 |     the index is not valid. | 
| 492 | */ | 
| 493 |  | 
| 494 | /*! | 
| 495 |     \internal | 
| 496 |  | 
| 497 |     Constructs an empty series object that is a child of \a parent. | 
| 498 |     When the series object is added to QChart, instance ownerships is transferred. | 
| 499 | */ | 
| 500 | QXYSeries::QXYSeries(QXYSeriesPrivate &d, QObject *parent) | 
| 501 |     : QAbstractSeries(d, parent) | 
| 502 | { | 
| 503 | } | 
| 504 |  | 
| 505 | /*! | 
| 506 |     Deletes the series. Series added to QChart instances are owned by them, | 
| 507 |     and are deleted when the QChart instances are deleted. | 
| 508 | */ | 
| 509 | QXYSeries::~QXYSeries() | 
| 510 | { | 
| 511 | } | 
| 512 |  | 
| 513 | /*! | 
| 514 |     Adds the data point with the coordinates \a x and \a y to the series. | 
| 515 |  */ | 
| 516 | void QXYSeries::append(qreal x, qreal y) | 
| 517 | { | 
| 518 |     append(point: QPointF(x, y)); | 
| 519 | } | 
| 520 |  | 
| 521 | /*! | 
| 522 |    \overload | 
| 523 |    Adds the data point \a point to the series. | 
| 524 |  */ | 
| 525 | void QXYSeries::append(const QPointF &point) | 
| 526 | { | 
| 527 |     Q_D(QXYSeries); | 
| 528 |  | 
| 529 |     if (isValidValue(point)) { | 
| 530 |         d->m_points << point; | 
| 531 |         emit pointAdded(index: d->m_points.count() - 1); | 
| 532 |     } | 
| 533 | } | 
| 534 |  | 
| 535 | /*! | 
| 536 |    \overload | 
| 537 |    Adds the list of data points specified by \a points to the series. | 
| 538 |  */ | 
| 539 | void QXYSeries::append(const QList<QPointF> &points) | 
| 540 | { | 
| 541 |     foreach (const QPointF &point , points) | 
| 542 |         append(point); | 
| 543 | } | 
| 544 |  | 
| 545 | /*! | 
| 546 |     Replaces the point with the coordinates \a oldX and \a oldY with the point | 
| 547 |     with the coordinates \a newX and \a newY. Does nothing if the old point does | 
| 548 |     not exist. | 
| 549 |  | 
| 550 |     \sa pointReplaced() | 
| 551 | */ | 
| 552 | void QXYSeries::replace(qreal oldX, qreal oldY, qreal newX, qreal newY) | 
| 553 | { | 
| 554 |     replace(oldPoint: QPointF(oldX, oldY), newPoint: QPointF(newX, newY)); | 
| 555 | } | 
| 556 |  | 
| 557 | /*! | 
| 558 |   Replaces the point specified by \a oldPoint with the one specified by | 
| 559 |   \a newPoint. | 
| 560 |   \sa pointReplaced() | 
| 561 | */ | 
| 562 | void QXYSeries::replace(const QPointF &oldPoint, const QPointF &newPoint) | 
| 563 | { | 
| 564 |     Q_D(QXYSeries); | 
| 565 |     int index = d->m_points.indexOf(t: oldPoint); | 
| 566 |     if (index == -1) | 
| 567 |         return; | 
| 568 |     replace(index, newPoint); | 
| 569 | } | 
| 570 |  | 
| 571 | /*! | 
| 572 |   Replaces the point at the position specified by \a index with the point that | 
| 573 |   has the coordinates \a newX and \a newY. | 
| 574 |   \sa pointReplaced() | 
| 575 | */ | 
| 576 | void QXYSeries::replace(int index, qreal newX, qreal newY) | 
| 577 | { | 
| 578 |     replace(index, newPoint: QPointF(newX, newY)); | 
| 579 | } | 
| 580 |  | 
| 581 | /*! | 
| 582 |   Replaces the point at the position specified by \a index with the point | 
| 583 |   specified by \a newPoint. | 
| 584 |   \sa pointReplaced() | 
| 585 | */ | 
| 586 | void QXYSeries::replace(int index, const QPointF &newPoint) | 
| 587 | { | 
| 588 |     Q_D(QXYSeries); | 
| 589 |     if (isValidValue(point: newPoint)) { | 
| 590 |         d->m_points[index] = newPoint; | 
| 591 |         emit pointReplaced(index); | 
| 592 |     } | 
| 593 | } | 
| 594 |  | 
| 595 | /*! | 
| 596 |   Replaces the current points with the points specified by \a points. | 
| 597 |   \note This is much faster than replacing data points one by one, | 
| 598 |   or first clearing all data, and then appending the new data. Emits QXYSeries::pointsReplaced() | 
| 599 |   when the points have been replaced. However, note that using the overload that takes | 
| 600 |   \c{QVector<QPointF>} as parameter is faster than using this overload. | 
| 601 |   \sa pointsReplaced() | 
| 602 | */ | 
| 603 | void QXYSeries::replace(QList<QPointF> points) | 
| 604 | { | 
| 605 |     replace(points: points.toVector()); | 
| 606 | } | 
| 607 |  | 
| 608 | /*! | 
| 609 |   Replaces the current points with the points specified by \a points. | 
| 610 |   \note This is much faster than replacing data points one by one, | 
| 611 |   or first clearing all data, and then appending the new data. Emits QXYSeries::pointsReplaced() | 
| 612 |   when the points have been replaced. | 
| 613 |   \sa pointsReplaced() | 
| 614 | */ | 
| 615 | void QXYSeries::replace(QVector<QPointF> points) | 
| 616 | { | 
| 617 |     Q_D(QXYSeries); | 
| 618 |     d->m_points = points; | 
| 619 |     emit pointsReplaced(); | 
| 620 | } | 
| 621 |  | 
| 622 | /*! | 
| 623 |   Removes the point that has the coordinates \a x and \a y from the series. | 
| 624 |   \sa pointRemoved() | 
| 625 | */ | 
| 626 | void QXYSeries::remove(qreal x, qreal y) | 
| 627 | { | 
| 628 |     remove(point: QPointF(x, y)); | 
| 629 | } | 
| 630 |  | 
| 631 | /*! | 
| 632 |   Removes the data point \a point from the series. | 
| 633 |   \sa pointRemoved() | 
| 634 | */ | 
| 635 | void QXYSeries::remove(const QPointF &point) | 
| 636 | { | 
| 637 |     Q_D(QXYSeries); | 
| 638 |     int index = d->m_points.indexOf(t: point); | 
| 639 |     if (index == -1) | 
| 640 |         return; | 
| 641 |     remove(index); | 
| 642 | } | 
| 643 |  | 
| 644 | /*! | 
| 645 |   Removes the point at the position specified by \a index from the series. | 
| 646 |   \sa pointRemoved() | 
| 647 | */ | 
| 648 | void QXYSeries::remove(int index) | 
| 649 | { | 
| 650 |     Q_D(QXYSeries); | 
| 651 |     d->m_points.remove(i: index); | 
| 652 |     emit pointRemoved(index); | 
| 653 | } | 
| 654 |  | 
| 655 | /*! | 
| 656 |   Removes the number of points specified by \a count from the series starting at | 
| 657 |   the position specified by \a index. | 
| 658 |   \sa pointsRemoved() | 
| 659 | */ | 
| 660 | void QXYSeries::removePoints(int index, int count) | 
| 661 | { | 
| 662 |     // This function doesn't overload remove as there is chance for it to get mixed up with | 
| 663 |     // remove(qreal, qreal) overload in some implicit casting cases. | 
| 664 |     Q_D(QXYSeries); | 
| 665 |     if (count > 0) { | 
| 666 |         d->m_points.remove(i: index, n: count); | 
| 667 |         emit pointsRemoved(index, count); | 
| 668 |     } | 
| 669 | } | 
| 670 |  | 
| 671 | /*! | 
| 672 |   Inserts the data point \a point in the series at the position specified by | 
| 673 |   \a index. | 
| 674 |   \sa pointAdded() | 
| 675 | */ | 
| 676 | void QXYSeries::insert(int index, const QPointF &point) | 
| 677 | { | 
| 678 |     Q_D(QXYSeries); | 
| 679 |     if (isValidValue(point)) { | 
| 680 |         index = qMax(a: 0, b: qMin(a: index, b: d->m_points.size())); | 
| 681 |         d->m_points.insert(i: index, t: point); | 
| 682 |         emit pointAdded(index); | 
| 683 |     } | 
| 684 | } | 
| 685 |  | 
| 686 | /*! | 
| 687 |   Removes all points from the series. | 
| 688 |   \sa pointsRemoved() | 
| 689 | */ | 
| 690 | void QXYSeries::clear() | 
| 691 | { | 
| 692 |     Q_D(QXYSeries); | 
| 693 |     removePoints(index: 0, count: d->m_points.size()); | 
| 694 | } | 
| 695 |  | 
| 696 | /*! | 
| 697 |     Returns the points in the series as a list. | 
| 698 |     Use pointsVector() for better performance. | 
| 699 | */ | 
| 700 | QList<QPointF> QXYSeries::points() const | 
| 701 | { | 
| 702 |     Q_D(const QXYSeries); | 
| 703 |     return d->m_points.toList(); | 
| 704 | } | 
| 705 |  | 
| 706 | /*! | 
| 707 |     Returns the points in the series as a vector. | 
| 708 |     This is more efficient than calling points(). | 
| 709 | */ | 
| 710 | QVector<QPointF> QXYSeries::pointsVector() const | 
| 711 | { | 
| 712 |     Q_D(const QXYSeries); | 
| 713 |     return d->m_points; | 
| 714 | } | 
| 715 |  | 
| 716 | /*! | 
| 717 |     Returns the data point at the position specified by \a index in the internal | 
| 718 |     points vector. | 
| 719 | */ | 
| 720 | const QPointF &QXYSeries::at(int index) const | 
| 721 | { | 
| 722 |     Q_D(const QXYSeries); | 
| 723 |     return d->m_points.at(i: index); | 
| 724 | } | 
| 725 |  | 
| 726 | /*! | 
| 727 |     Returns the number of data points in a series. | 
| 728 | */ | 
| 729 | int QXYSeries::count() const | 
| 730 | { | 
| 731 |     Q_D(const QXYSeries); | 
| 732 |     return d->m_points.count(); | 
| 733 | } | 
| 734 |  | 
| 735 |  | 
| 736 | /*! | 
| 737 |     Sets the pen used for drawing points on the chart to \a pen. If the pen is | 
| 738 |     not defined, the pen from the chart theme is used. | 
| 739 |     \sa QChart::setTheme() | 
| 740 | */ | 
| 741 | void QXYSeries::setPen(const QPen &pen) | 
| 742 | { | 
| 743 |     Q_D(QXYSeries); | 
| 744 |     if (d->m_pen != pen) { | 
| 745 |         bool emitColorChanged = d->m_pen.color() != pen.color(); | 
| 746 |         d->m_pen = pen; | 
| 747 |         emit d->updated(); | 
| 748 |         if (emitColorChanged) | 
| 749 |             emit colorChanged(color: pen.color()); | 
| 750 |         emit penChanged(pen); | 
| 751 |     } | 
| 752 | } | 
| 753 |  | 
| 754 | QPen QXYSeries::pen() const | 
| 755 | { | 
| 756 |     Q_D(const QXYSeries); | 
| 757 |     if (d->m_pen == QChartPrivate::defaultPen()) | 
| 758 |         return QPen(); | 
| 759 |     else | 
| 760 |         return d->m_pen; | 
| 761 | } | 
| 762 |  | 
| 763 | /*! | 
| 764 |     Sets the brush used for drawing points on the chart to \a brush. If the | 
| 765 |     brush is not defined, the brush from the chart theme setting is used. | 
| 766 |     \sa QChart::setTheme() | 
| 767 | */ | 
| 768 | void QXYSeries::setBrush(const QBrush &brush) | 
| 769 | { | 
| 770 |     Q_D(QXYSeries); | 
| 771 |     if (d->m_brush != brush) { | 
| 772 |         d->m_brush = brush; | 
| 773 |         emit d->updated(); | 
| 774 |     } | 
| 775 | } | 
| 776 |  | 
| 777 | QBrush QXYSeries::brush() const | 
| 778 | { | 
| 779 |     Q_D(const QXYSeries); | 
| 780 |     if (d->m_brush == QChartPrivate::defaultBrush()) | 
| 781 |         return QBrush(); | 
| 782 |     else | 
| 783 |         return d->m_brush; | 
| 784 | } | 
| 785 |  | 
| 786 | void QXYSeries::setColor(const QColor &color) | 
| 787 | { | 
| 788 |     QPen p = pen(); | 
| 789 |     if (p.color() != color) { | 
| 790 |         p.setColor(color); | 
| 791 |         setPen(p); | 
| 792 |     } | 
| 793 | } | 
| 794 |  | 
| 795 | QColor QXYSeries::color() const | 
| 796 | { | 
| 797 |     return pen().color(); | 
| 798 | } | 
| 799 |  | 
| 800 | void QXYSeries::setPointsVisible(bool visible) | 
| 801 | { | 
| 802 |     Q_D(QXYSeries); | 
| 803 |     if (d->m_pointsVisible != visible) { | 
| 804 |         d->m_pointsVisible = visible; | 
| 805 |         emit d->updated(); | 
| 806 |     } | 
| 807 | } | 
| 808 |  | 
| 809 | bool QXYSeries::pointsVisible() const | 
| 810 | { | 
| 811 |     Q_D(const QXYSeries); | 
| 812 |     return d->m_pointsVisible; | 
| 813 | } | 
| 814 |  | 
| 815 | void QXYSeries::setPointLabelsFormat(const QString &format) | 
| 816 | { | 
| 817 |     Q_D(QXYSeries); | 
| 818 |     if (d->m_pointLabelsFormat != format) { | 
| 819 |         d->m_pointLabelsFormat = format; | 
| 820 |         emit pointLabelsFormatChanged(format); | 
| 821 |     } | 
| 822 | } | 
| 823 |  | 
| 824 | QString QXYSeries::pointLabelsFormat() const | 
| 825 | { | 
| 826 |     Q_D(const QXYSeries); | 
| 827 |     return d->m_pointLabelsFormat; | 
| 828 | } | 
| 829 |  | 
| 830 | void QXYSeries::setPointLabelsVisible(bool visible) | 
| 831 | { | 
| 832 |     Q_D(QXYSeries); | 
| 833 |     if (d->m_pointLabelsVisible != visible) { | 
| 834 |         d->m_pointLabelsVisible = visible; | 
| 835 |         emit pointLabelsVisibilityChanged(visible); | 
| 836 |     } | 
| 837 | } | 
| 838 |  | 
| 839 | bool QXYSeries::pointLabelsVisible() const | 
| 840 | { | 
| 841 |     Q_D(const QXYSeries); | 
| 842 |     return d->m_pointLabelsVisible; | 
| 843 | } | 
| 844 |  | 
| 845 | void QXYSeries::setPointLabelsFont(const QFont &font) | 
| 846 | { | 
| 847 |     Q_D(QXYSeries); | 
| 848 |     if (d->m_pointLabelsFont != font) { | 
| 849 |         d->m_pointLabelsFont = font; | 
| 850 |         emit pointLabelsFontChanged(font); | 
| 851 |     } | 
| 852 | } | 
| 853 |  | 
| 854 | QFont QXYSeries::pointLabelsFont() const | 
| 855 | { | 
| 856 |     Q_D(const QXYSeries); | 
| 857 |     return d->m_pointLabelsFont; | 
| 858 | } | 
| 859 |  | 
| 860 | void QXYSeries::setPointLabelsColor(const QColor &color) | 
| 861 | { | 
| 862 |     Q_D(QXYSeries); | 
| 863 |     if (d->m_pointLabelsColor != color) { | 
| 864 |         d->m_pointLabelsColor = color; | 
| 865 |         emit pointLabelsColorChanged(color); | 
| 866 |     } | 
| 867 | } | 
| 868 |  | 
| 869 | QColor QXYSeries::pointLabelsColor() const | 
| 870 | { | 
| 871 |     Q_D(const QXYSeries); | 
| 872 |     if (d->m_pointLabelsColor == QChartPrivate::defaultPen().color()) | 
| 873 |         return QPen().color(); | 
| 874 |     else | 
| 875 |         return d->m_pointLabelsColor; | 
| 876 | } | 
| 877 |  | 
| 878 | void QXYSeries::setPointLabelsClipping(bool enabled) | 
| 879 | { | 
| 880 |     Q_D(QXYSeries); | 
| 881 |     if (d->m_pointLabelsClipping != enabled) { | 
| 882 |         d->m_pointLabelsClipping = enabled; | 
| 883 |         emit pointLabelsClippingChanged(clipping: enabled); | 
| 884 |     } | 
| 885 | } | 
| 886 |  | 
| 887 | bool QXYSeries::pointLabelsClipping() const | 
| 888 | { | 
| 889 |     Q_D(const QXYSeries); | 
| 890 |     return d->m_pointLabelsClipping; | 
| 891 | } | 
| 892 |  | 
| 893 | /*! | 
| 894 |     Stream operator for adding the data point \a point to the series. | 
| 895 |     \sa append() | 
| 896 | */ | 
| 897 | QXYSeries &QXYSeries::operator<< (const QPointF &point) | 
| 898 | { | 
| 899 |     append(point); | 
| 900 |     return *this; | 
| 901 | } | 
| 902 |  | 
| 903 |  | 
| 904 | /*! | 
| 905 |     Stream operator for adding the list of data points specified by \a points | 
| 906 |     to the series. | 
| 907 |     \sa append() | 
| 908 | */ | 
| 909 |  | 
| 910 | QXYSeries &QXYSeries::operator<< (const QList<QPointF>& points) | 
| 911 | { | 
| 912 |     append(points); | 
| 913 |     return *this; | 
| 914 | } | 
| 915 |  | 
| 916 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | 
| 917 |  | 
| 918 |  | 
| 919 | QXYSeriesPrivate::QXYSeriesPrivate(QXYSeries *q) | 
| 920 |     : QAbstractSeriesPrivate(q), | 
| 921 |       m_pen(QChartPrivate::defaultPen()), | 
| 922 |       m_brush(QChartPrivate::defaultBrush()), | 
| 923 |       m_pointsVisible(false), | 
| 924 |       m_pointLabelsFormat(QLatin1String("@xPoint, @yPoint" )), | 
| 925 |       m_pointLabelsVisible(false), | 
| 926 |       m_pointLabelsFont(QChartPrivate::defaultFont()), | 
| 927 |       m_pointLabelsColor(QChartPrivate::defaultPen().color()), | 
| 928 |       m_pointLabelsClipping(true) | 
| 929 | { | 
| 930 | } | 
| 931 |  | 
| 932 | void QXYSeriesPrivate::initializeDomain() | 
| 933 | { | 
| 934 |     qreal minX(0); | 
| 935 |     qreal minY(0); | 
| 936 |     qreal maxX(1); | 
| 937 |     qreal maxY(1); | 
| 938 |  | 
| 939 |     Q_Q(QXYSeries); | 
| 940 |  | 
| 941 |     const QVector<QPointF> &points = q->pointsVector(); | 
| 942 |  | 
| 943 |     if (!points.isEmpty()) { | 
| 944 |         minX = points[0].x(); | 
| 945 |         minY = points[0].y(); | 
| 946 |         maxX = minX; | 
| 947 |         maxY = minY; | 
| 948 |  | 
| 949 |         for (int i = 0; i < points.count(); i++) { | 
| 950 |             qreal x = points[i].x(); | 
| 951 |             qreal y = points[i].y(); | 
| 952 |             minX = qMin(a: minX, b: x); | 
| 953 |             minY = qMin(a: minY, b: y); | 
| 954 |             maxX = qMax(a: maxX, b: x); | 
| 955 |             maxY = qMax(a: maxY, b: y); | 
| 956 |         } | 
| 957 |     } | 
| 958 |  | 
| 959 |     domain()->setRange(minX, maxX, minY, maxY); | 
| 960 | } | 
| 961 |  | 
| 962 | QList<QLegendMarker*> QXYSeriesPrivate::createLegendMarkers(QLegend* legend) | 
| 963 | { | 
| 964 |     Q_Q(QXYSeries); | 
| 965 |     QList<QLegendMarker*> list; | 
| 966 |     return list << new QXYLegendMarker(q,legend); | 
| 967 | } | 
| 968 |  | 
| 969 | void QXYSeriesPrivate::initializeAxes() | 
| 970 | { | 
| 971 |  | 
| 972 | } | 
| 973 |  | 
| 974 | QAbstractAxis::AxisType QXYSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const | 
| 975 | { | 
| 976 |     Q_UNUSED(orientation); | 
| 977 |     return QAbstractAxis::AxisTypeValue; | 
| 978 | } | 
| 979 |  | 
| 980 | QAbstractAxis* QXYSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const | 
| 981 | { | 
| 982 |     Q_UNUSED(orientation); | 
| 983 |     return new QValueAxis; | 
| 984 | } | 
| 985 |  | 
| 986 | void QXYSeriesPrivate::initializeAnimations(QtCharts::QChart::AnimationOptions options, | 
| 987 |                                             int duration, QEasingCurve &curve) | 
| 988 | { | 
| 989 |     XYChart *item = static_cast<XYChart *>(m_item.data()); | 
| 990 |     Q_ASSERT(item); | 
| 991 |     if (item->animation()) | 
| 992 |         item->animation()->stopAndDestroyLater(); | 
| 993 |  | 
| 994 |     if (options.testFlag(flag: QChart::SeriesAnimations)) | 
| 995 |         item->setAnimation(new XYAnimation(item, duration, curve)); | 
| 996 |     else | 
| 997 |         item->setAnimation(0); | 
| 998 |     QAbstractSeriesPrivate::initializeAnimations(options, duration, curve); | 
| 999 | } | 
| 1000 |  | 
| 1001 | void QXYSeriesPrivate::drawSeriesPointLabels(QPainter *painter, const QVector<QPointF> &points, | 
| 1002 |                                              const int offset) | 
| 1003 | { | 
| 1004 |     if (points.size() == 0) | 
| 1005 |         return; | 
| 1006 |  | 
| 1007 |     static const QString xPointTag(QLatin1String("@xPoint" )); | 
| 1008 |     static const QString yPointTag(QLatin1String("@yPoint" )); | 
| 1009 |     const int labelOffset = offset + 2; | 
| 1010 |  | 
| 1011 |     QFont f(m_pointLabelsFont); | 
| 1012 |     f.setPixelSize(QFontInfo(m_pointLabelsFont).pixelSize()); | 
| 1013 |     painter->setFont(f); | 
| 1014 |     painter->setPen(QPen(m_pointLabelsColor)); | 
| 1015 |     QFontMetrics fm(painter->font()); | 
| 1016 |     // m_points is used for the label here as it has the series point information | 
| 1017 |     // points variable passed is used for positioning because it has the coordinates | 
| 1018 |     const int pointCount = qMin(a: points.size(), b: m_points.size()); | 
| 1019 |     for (int i(0); i < pointCount; i++) { | 
| 1020 |         QString pointLabel = m_pointLabelsFormat; | 
| 1021 |         pointLabel.replace(before: xPointTag, after: presenter()->numberToString(value: m_points.at(i).x())); | 
| 1022 |         pointLabel.replace(before: yPointTag, after: presenter()->numberToString(value: m_points.at(i).y())); | 
| 1023 |  | 
| 1024 |         // Position text in relation to the point | 
| 1025 |         int pointLabelWidth = fm.horizontalAdvance(pointLabel); | 
| 1026 |         QPointF position(points.at(i)); | 
| 1027 |         position.setX(position.x() - pointLabelWidth / 2); | 
| 1028 |         position.setY(position.y() - labelOffset); | 
| 1029 |  | 
| 1030 |         painter->drawText(p: position, s: pointLabel); | 
| 1031 |     } | 
| 1032 | } | 
| 1033 |  | 
| 1034 | QT_CHARTS_END_NAMESPACE | 
| 1035 |  | 
| 1036 | #include "moc_qxyseries.cpp" | 
| 1037 | #include "moc_qxyseries_p.cpp" | 
| 1038 |  |