1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "graphs2d/qabstractseries.h"
5#include <QtGraphs/qxyseries.h>
6#include <private/qxyseries_p.h>
7#include <private/charthelpers_p.h>
8
9QT_BEGIN_NAMESPACE
10
11/*!
12 \class QXYSeries
13 \inmodule QtGraphs
14 \ingroup graphs_2D
15 \brief The QXYSeries class is a parent class for all x & y series classes.
16
17 In QXYSeries, data points are defined as a list of QPointF, defining X and Y positions.
18
19 \sa QLineSeries, QScatterSeries
20*/
21/*!
22 \qmltype XYSeries
23 \nativetype QXYSeries
24 \inqmlmodule QtGraphs
25 \ingroup graphs_qml_2D
26 \inherits AbstractSeries
27 \brief A parent type for all x & y series types.
28
29 In XYSeries, data points are defined as a list of point types, defining X and Y positions.
30*/
31
32/*!
33 \fn void QXYSeries::pointReplaced(qsizetype index)
34 This signal is emitted when a point is replaced at the position specified by
35 \a index.
36 \sa replace()
37*/
38/*!
39 \qmlsignal XYSeries::pointReplaced(int index)
40 This signal is emitted when a point is replaced at the position specified by
41 \a index.
42*/
43
44/*!
45 \fn void QXYSeries::pointsReplaced()
46 This signal is emitted when all points are replaced.
47*/
48/*!
49 \qmlsignal XYSeries::pointsReplaced()
50 This signal is emitted when all points are replaced.
51*/
52
53/*!
54 \fn void QXYSeries::pointsAdded(qsizetype start, qsizetype end)
55 This signal is emitted when a list of points is appended.
56 The indexes of the new added points are between \a start and \a end.
57 \since 6.9
58*/
59/*!
60 \qmlsignal XYSeries::pointsAdded(int start, int end)
61 This signal is emitted when a list of points is appended.
62 The indexes of the new added points are between \a start and \a end.
63 \since 6.9
64*/
65
66/*!
67 \qmlsignal XYSeries::colorChanged(color color)
68 This signal is emitted when the line color changes to \a color.
69*/
70
71/*!
72 \qmlsignal XYSeries::selectedColorChanged(color color)
73 This signal is emitted when the color of selected series changes to \a color.
74*/
75
76/*!
77 \qmlsignal XYSeries::selectedPointsChanged()
78 This signal is emitted when the set of selected points changes.
79*/
80
81/*!
82 \qmlsignal XYSeries::pointMarkerChanged()
83 This signal is emitted when a point is changed.
84*/
85
86/*!
87 \qmlsignal XYSeries::draggableChanged()
88 This signal is emitted when a series becomes draggable by a mouse/touch or
89 becomes fixed.
90*/
91
92/*!
93 \qmlsignal XYSeries::clicked(point point)
94 This signal is emitted when the user clicks or taps the \a point in the graph.
95*/
96
97/*!
98 \qmlsignal XYSeries::doubleClicked(point point)
99 This signal is emitted when the user double-clicks or double-taps the data \a point in
100 the graph. The \a point is the point where the first press was triggered.
101 This signal always occurs after \l clicked.
102*/
103
104/*!
105 \qmlsignal XYSeries::pressed(point point)
106 This signal is emitted when the user presses the data \a point in the graph
107 and holds down the mouse button or gesture.
108*/
109
110/*!
111 \qmlsignal XYSeries::released(point point)
112 This signal is emitted when the user releases the previously pressed mouse
113 button or gesture on the data \a point.
114*/
115
116QXYSeries::QXYSeries(QXYSeriesPrivate &dd, QObject *parent)
117 : QAbstractSeries(dd, parent)
118{
119 QObject::connect(sender: this, signal: &QXYSeries::selectedPointsChanged, context: this, slot: &QAbstractSeries::update);
120 QObject::connect(sender: this, signal: &QXYSeries::pointAdded, context: this, slot: &QAbstractSeries::update);
121 QObject::connect(sender: this, signal: &QXYSeries::pointsAdded, context: this, slot: &QAbstractSeries::update);
122 QObject::connect(sender: this, signal: &QXYSeries::pointReplaced, context: this, slot: &QAbstractSeries::update);
123 QObject::connect(sender: this, signal: &QXYSeries::pointsReplaced, context: this, slot: &QAbstractSeries::update);
124 QObject::connect(sender: this, signal: &QXYSeries::pointRemoved, context: this, slot: &QAbstractSeries::update);
125 QObject::connect(sender: this, signal: &QXYSeries::pointsRemoved, context: this, slot: &QAbstractSeries::update);
126}
127
128/*!
129 \qmlmethod XYSeries::append(real x, real y)
130 Appends a point with the coordinates \a x and \a y to the series.
131*/
132/*!
133 Appends a point with the coordinates \a x and \a y to the series.
134*/
135void QXYSeries::append(qreal x, qreal y)
136{
137 append(point: QPointF(x, y));
138}
139
140/*!
141 \qmlmethod XYSeries::append(point point)
142 Appends a point with the coordinates \a point to the series.
143*/
144/*!
145 Appends a point with the coordinates \a point to the series.
146*/
147void QXYSeries::append(QPointF point)
148{
149 Q_D(QXYSeries);
150 if (isValidValue(point)) {
151 if (d->m_graphTransition && d->m_graphTransition->initialized()
152 && d->m_graphTransition->contains(type: QGraphAnimation::GraphAnimationType::GraphPoint)) {
153 d->m_graphTransition->stop();
154 d->m_graphTransition->onPointChanged(type: QGraphTransition::TransitionType::PointAdded,
155 index: d->m_points.size(),
156 point);
157 } else {
158 d->m_points << point;
159 emit pointAdded(index: d->m_points.size() - 1);
160 emit countChanged();
161 }
162 }
163}
164
165/*!
166 \qmlmethod XYSeries::append(list<point> points)
167 Appends points with the coordinates \a points to the series.
168 \note This is much faster than appending data points one by one.
169 Emits \l pointsAdded when the points have been added.
170*/
171/*!
172 Appends points with the coordinates \a points to the series.
173 \note This is much faster than appending data points one by one.
174 Emits \l pointsAdded when the points have been added.
175*/
176void QXYSeries::append(const QList<QPointF> &points)
177{
178 Q_D(QXYSeries);
179 d->append(points);
180}
181
182/*!
183 \qmlmethod XYSeries::replace(real oldX, real oldY, real newX, real newY)
184 Replaces the point with the coordinates \a oldX and \a oldY with the point
185 with the coordinates \a newX and \a newY. Does nothing if the old point does
186 not exist.
187*/
188/*!
189 Replaces the point with the coordinates \a oldX and \a oldY with the point
190 with the coordinates \a newX and \a newY. Does nothing if the old point does
191 not exist.
192*/
193void QXYSeries::replace(qreal oldX, qreal oldY, qreal newX, qreal newY)
194{
195 replace(oldPoint: QPointF(oldX, oldY), newPoint: QPointF(newX, newY));
196}
197
198/*!
199 \qmlmethod XYSeries::replace(point oldPoint, point newPoint)
200 Replaces the point with the coordinates \a oldPoint with the point
201 with the coordinates \a newPoint. Does nothing if the old point does
202 not exist.
203*/
204/*!
205 Replaces the point with the coordinates \a oldPoint with the point
206 with the coordinates \a newPoint. Does nothing if the old point does
207 not exist.
208*/
209void QXYSeries::replace(QPointF oldPoint, QPointF newPoint)
210{
211 Q_D(QXYSeries);
212 qsizetype index = d->m_points.indexOf(t: oldPoint);
213 if (index == -1)
214 return;
215 replace(index, newPoint);
216}
217
218/*!
219 \qmlmethod XYSeries::replace(int index, real newX, real newY)
220 Replaces the point at the position specified by \a index with the point
221 that has the coordinates \a newX and \a newY.
222*/
223/*!
224 Replaces the point at the position specified by \a index with the point
225 that has the coordinates \a newX and \a newY.
226*/
227void QXYSeries::replace(qsizetype index, qreal newX, qreal newY)
228{
229 replace(index, newPoint: QPointF(newX, newY));
230}
231
232/*!
233 \qmlmethod XYSeries::replace(int index, point newPoint)
234 Replaces the point at the position specified by \a index with the point
235 that has the coordinates \a newPoint.
236*/
237/*!
238 Replaces the point at the position specified by \a index with the point
239 that has the coordinates \a newPoint.
240*/
241void QXYSeries::replace(qsizetype index, QPointF newPoint)
242{
243 Q_D(QXYSeries);
244
245 if (index < 0 || index >= d->m_points.size())
246 return;
247
248 if (isValidValue(point: newPoint)) {
249 if (d->m_graphTransition && d->m_graphTransition->initialized()
250 && d->m_graphTransition->contains(type: QGraphAnimation::GraphAnimationType::GraphPoint)) {
251 d->m_graphTransition->stop();
252 d->m_graphTransition->onPointChanged(type: QGraphTransition::TransitionType::PointReplaced,
253 index,
254 point: newPoint);
255 } else {
256 d->m_points[index] = newPoint;
257 emit pointReplaced(index);
258 }
259 }
260}
261
262/*!
263 \qmlmethod XYSeries::replace(list<point> points)
264 Replaces the current points with the points specified by \a points
265 \note This is much faster than replacing data points one by one, or first
266 clearing all data, and then appending the new data. Emits \l pointsReplaced
267 when the points have been replaced.
268*/
269/*!
270 Replaces the current points with the points specified by \a points
271 \note This is much faster than replacing data points one by one, or first
272 clearing all data, and then appending the new data. Emits \l pointsReplaced
273 when the points have been replaced.
274*/
275void QXYSeries::replace(const QList<QPointF> &points)
276{
277 Q_D(QXYSeries);
278 bool hasDifferentSize = d->m_points.size() != points.size();
279 d->m_points = points;
280 emit pointsReplaced();
281 if (hasDifferentSize)
282 emit countChanged();
283}
284
285/*!
286 \qmlmethod XYSeries::remove(real x, real y)
287 Removes the point with the coordinates \a x and \a y from the series. Does
288 nothing if the point does not exist.
289*/
290/*!
291 Removes the point with the coordinates \a x and \a y from the series. Does
292 nothing if the point does not exist.
293*/
294void QXYSeries::remove(qreal x, qreal y)
295{
296 remove(point: QPointF(x, y));
297}
298
299/*!
300 \qmlmethod XYSeries::remove(point point)
301 Removes the point with the coordinates \a point from the series. Does
302 nothing if the point does not exist.
303*/
304/*!
305 Removes the point with the coordinates \a point from the series. Does
306 nothing if the point does not exist.
307*/
308void QXYSeries::remove(QPointF point)
309{
310 Q_D(QXYSeries);
311 qsizetype index = d->m_points.indexOf(t: point);
312 if (index == -1)
313 return;
314 remove(index);
315}
316
317/*!
318 \qmlmethod XYSeries::remove(int index)
319 Removes the point at the position specified by \a index from the series.
320*/
321/*!
322 Removes the point at the position specified by \a index from the series.
323*/
324void QXYSeries::remove(qsizetype index)
325{
326 Q_D(QXYSeries);
327
328 if (index < 0 || index >= d->m_points.size())
329 return;
330
331 if (d->m_graphTransition && d->m_graphTransition->initialized()
332 && d->m_graphTransition->contains(type: QGraphAnimation::GraphAnimationType::GraphPoint)) {
333 d->m_graphTransition->stop();
334 d->m_graphTransition->onPointChanged(type: QGraphTransition::TransitionType::PointRemoved,
335 index,
336 point: {});
337 } else {
338 d->m_points.remove(i: index);
339 bool callSignal = false;
340 d->setPointSelected(index, selected: false, callSignal);
341
342 emit pointRemoved(index);
343 emit countChanged();
344 if (callSignal)
345 emit selectedPointsChanged();
346 }
347}
348
349/*!
350 \qmlmethod XYSeries::removeMultiple(int index, int count)
351 Removes the number of points specified by \a count from the series starting
352 at the position specified by \a index.
353*/
354/*!
355 Removes the number of points specified by \a count from the series starting
356 at the position specified by \a index.
357*/
358void QXYSeries::removeMultiple(qsizetype index, qsizetype count)
359{
360 // This function doesn't overload remove as there is chance for it to get mixed up with
361 // remove(qreal, qreal) overload in some implicit casting cases.
362 Q_D(QXYSeries);
363
364 if (index < 0 || count < 1 || index + count > d->m_points.size())
365 return;
366
367 if (count > 0) {
368 if (d->m_graphTransition && d->m_graphTransition->initialized()
369 && d->m_graphTransition->contains(type: QGraphAnimation::GraphAnimationType::GraphPoint)) {
370 d->m_graphTransition->stop();
371 }
372
373 d->m_points.remove(i: index, n: count);
374
375 bool callSignal = false;
376 if (!d->m_selectedPoints.empty()) {
377 QSet<qsizetype> selectedAfterRemoving;
378
379 for (const qsizetype &selectedPointIndex : std::as_const(t&: d->m_selectedPoints)) {
380 if (selectedPointIndex < index) {
381 selectedAfterRemoving << selectedPointIndex;
382 } else if (selectedPointIndex >= index + count) {
383 selectedAfterRemoving << selectedPointIndex - int(count);
384 callSignal = true;
385 } else {
386 callSignal = true;
387 }
388 }
389
390 d->m_selectedPoints = selectedAfterRemoving;
391 }
392
393 emit pointsRemoved(index, count);
394 emit countChanged();
395 if (callSignal)
396 emit selectedPointsChanged();
397 }
398}
399
400/*!
401 \qmlmethod bool XYSeries::take(point point)
402 Takes a point, specified by \a point, out of the series if found. Returns \c true if
403 the operation is successful.
404*/
405/*!
406 Takes a point, specified by \a point, out of the series if found. Returns \c true if
407 the operation is successful.
408*/
409bool QXYSeries::take(QPointF point)
410{
411 Q_D(QXYSeries);
412
413 for (int i = 0; i < d->m_points.size(); ++i) {
414 if (d->m_points[i] == point) {
415 d->m_points.removeAt(i);
416 return true;
417 }
418 }
419
420 return false;
421}
422
423/*!
424 \qmlmethod XYSeries::insert(int index, point point)
425 Inserts a point with the coordinates \a point to the position specified
426 by \a index in the series. If the index is 0 or less than 0, the point is
427 prepended to the list of points. If the index is equal to or greater than
428 than the number of points in the series, the point is appended to the
429 list of points.
430*/
431/*!
432 Inserts a point with the coordinates \a point to the position specified
433 by \a index in the series. If the index is 0 or less than 0, the point is
434 prepended to the list of points. If the index is equal to or greater than
435 than the number of points in the series, the point is appended to the
436 list of points.
437*/
438void QXYSeries::insert(qsizetype index, QPointF point)
439{
440 Q_D(QXYSeries);
441
442 if (isValidValue(point)) {
443 index = qMax(a: 0, b: qMin(a: index, b: d->m_points.size()));
444
445 d->m_points.insert(i: index, t: point);
446
447 bool callSignal = false;
448 if (!d->m_selectedPoints.isEmpty()) {
449 // if point was inserted we need to move already selected points by 1
450 QSet<qsizetype> selectedAfterInsert;
451 for (const auto &value : std::as_const(t&: d->m_selectedPoints)) {
452 if (value >= index) {
453 selectedAfterInsert << value + 1;
454 callSignal = true;
455 } else {
456 selectedAfterInsert << value;
457 }
458 }
459 d->m_selectedPoints = selectedAfterInsert;
460 }
461
462 emit pointAdded(index);
463 if (callSignal)
464 emit selectedPointsChanged();
465 }
466}
467
468/*!
469 \qmlmethod XYSeries::clear()
470 Removes all points from the series.
471*/
472/*!
473 Removes all points from the series.
474*/
475void QXYSeries::clear()
476{
477 Q_D(QXYSeries);
478 removeMultiple(index: 0, count: d->m_points.size());
479}
480
481/*!
482 \qmlmethod bool XYSeries::isPointSelected(int index)
483 Returns true if point at given \a index is among selected points and false otherwise.
484 \note Selected points are drawn using the selected color if it was specified.
485 \sa selectedPoints, setPointSelected(), selectedColor
486 */
487/*!
488 Returns true if point at given \a index is among selected points and false otherwise.
489 \note Selected points are drawn using the selected color if it was specified.
490 \sa selectedPoints, setPointSelected(), setSelectedColor()
491 */
492bool QXYSeries::isPointSelected(qsizetype index) const
493{
494 Q_D(const QXYSeries);
495 return d->isPointSelected(index);
496}
497
498/*!
499 \qmlmethod XYSeries::selectPoint(int index)
500 Marks point at \a index as selected.
501 \note Emits QXYSeries::selectedPointsChanged
502 \sa setPointSelected()
503 */
504/*!
505 Marks point at \a index as selected.
506 \note Emits QXYSeries::selectedPointsChanged
507 \sa setPointSelected()
508 */
509void QXYSeries::selectPoint(qsizetype index)
510{
511 setPointSelected(index, selected: true);
512}
513
514/*!
515 \qmlmethod XYSeries::deselectPoint(int index)
516 Deselects point at given \a index.
517 \note Emits QXYSeries::selectedPointsChanged
518 \sa setPointSelected()
519 */
520/*!
521 Deselects point at given \a index.
522 \note Emits QXYSeries::selectedPointsChanged
523 \sa setPointSelected()
524 */
525void QXYSeries::deselectPoint(qsizetype index)
526{
527 setPointSelected(index, selected: false);
528}
529
530/*!
531 \qmlmethod XYSeries::setPointSelected(int index, bool selected)
532 Marks point at given \a index as either selected or deselected as specified by \a selected.
533 \note Selected points are drawn using the selected color if it was specified. Emits QXYSeries::selectedPointsChanged
534 \sa selectAllPoints(), selectedColor
535 */
536/*!
537 Marks point at given \a index as either selected or deselected as specified by \a selected.
538 \note Selected points are drawn using the selected color if it was specified. Emits QXYSeries::selectedPointsChanged
539 \sa selectAllPoints(), setSelectedColor()
540 */
541void QXYSeries::setPointSelected(qsizetype index, bool selected)
542{
543 Q_D(QXYSeries);
544
545 bool callSignal = false;
546 d->setPointSelected(index, selected, callSignal);
547
548 if (callSignal)
549 emit selectedPointsChanged();
550}
551
552/*!
553 \qmlmethod XYSeries::selectAllPoints()
554 Marks all points in the series as selected,
555 \note Emits QXYSeries::selectedPointsChanged
556 \sa setPointSelected()
557 */
558/*!
559 Marks all points in the series as selected,
560 \note Emits QXYSeries::selectedPointsChanged
561 \sa setPointSelected()
562 */
563void QXYSeries::selectAllPoints()
564{
565 Q_D(QXYSeries);
566
567 bool callSignal = false;
568 for (int i = 0; i < d->m_points.size(); ++i)
569 d->setPointSelected(index: i, selected: true, callSignal);
570
571 if (callSignal)
572 emit selectedPointsChanged();
573}
574
575/*!
576 \qmlmethod XYSeries::deselectAllPoints()
577 Deselects all points in the series.
578 \note Emits QXYSeries::selectedPointsChanged
579 \sa setPointSelected()
580 */
581/*!
582 Deselects all points in the series.
583 \note Emits QXYSeries::selectedPointsChanged
584 \sa setPointSelected()
585 */
586void QXYSeries::deselectAllPoints()
587{
588 Q_D(QXYSeries);
589
590 bool callSignal = false;
591 for (int i = 0; i < d->m_points.size(); ++i)
592 d->setPointSelected(index: i, selected: false, callSignal);
593
594 if (callSignal)
595 emit selectedPointsChanged();
596}
597
598/*!
599 \qmlmethod XYSeries::selectPoints(list<int> indexes)
600 Marks multiple points passed in a \a indexes list as selected.
601 \note Emits QXYSeries::selectedPointsChanged
602 \sa setPointSelected()
603 */
604/*!
605 Marks multiple points passed in a \a indexes list as selected.
606 \note Emits QXYSeries::selectedPointsChanged
607 \sa setPointSelected()
608 */
609void QXYSeries::selectPoints(const QList<qsizetype> &indexes)
610{
611 Q_D(QXYSeries);
612
613 bool callSignal = false;
614 for (const qsizetype &index : indexes)
615 d->setPointSelected(index, selected: true, callSignal);
616
617 if (callSignal)
618 emit selectedPointsChanged();
619}
620
621/*!
622 \qmlmethod XYSeries::deselectPoints(list<int> indexes)
623 Marks multiple points passed in a \a indexes list as deselected.
624 \note Emits QXYSeries::selectedPointsChanged
625 \sa setPointSelected()
626 */
627/*!
628 Marks multiple points passed in a \a indexes list as deselected.
629 \note Emits QXYSeries::selectedPointsChanged
630 \sa setPointSelected()
631 */
632void QXYSeries::deselectPoints(const QList<qsizetype> &indexes)
633{
634 Q_D(QXYSeries);
635
636 bool callSignal = false;
637 for (const qsizetype &index : indexes)
638 d->setPointSelected(index, selected: false, callSignal);
639
640 if (callSignal)
641 emit selectedPointsChanged();
642}
643
644/*!
645 \qmlmethod XYSeries::toggleSelection(list<int> indexes)
646 Changes selection state of points at given \a indexes to the opposite one.
647 \note Emits QXYSeries::selectedPointsChanged
648 \sa setPointSelected()
649 */
650/*!
651 Changes selection state of points at given \a indexes to the opposite one.
652 \note Emits QXYSeries::selectedPointsChanged
653 \sa setPointSelected()
654 */
655void QXYSeries::toggleSelection(const QList<qsizetype> &indexes)
656{
657 Q_D(QXYSeries);
658
659 bool callSignal = false;
660 for (const qsizetype &index : indexes)
661 d->setPointSelected(index, selected: !isPointSelected(index), callSignal);
662
663 if (callSignal)
664 emit selectedPointsChanged();
665}
666
667/*!
668 \property QXYSeries::selectedPoints
669 \brief The indexes of the points which are currently selected.
670*/
671/*!
672 \qmlproperty list<int> XYSeries::selectedPoints
673 The indexes of the points which are currently selected.
674*/
675
676/*!
677 Returns a list of points indexes marked as selected.
678 Selected points are visible regardless of points visibility.
679 \sa setPointSelected()
680 */
681QList<qsizetype> QXYSeries::selectedPoints() const
682{
683 Q_D(const QXYSeries);
684 return QList<qsizetype>(d->m_selectedPoints.begin(), d->m_selectedPoints.end());
685}
686
687/*!
688 \property QXYSeries::count
689 \brief Returns the number of data points in a series.
690*/
691/*!
692 \qmlproperty int XYSeries::count
693 Returns the number of data points in a series.
694*/
695qsizetype QXYSeries::count() const
696{
697 Q_D(const QXYSeries);
698 return d->m_points.size();
699}
700
701/*!
702 Returns the points in the series.
703*/
704QList<QPointF> QXYSeries::points() const
705{
706 Q_D(const QXYSeries);
707 return d->m_points;
708}
709
710/*!
711 \qmlmethod point XYSeries::at(int index)
712 Returns the point at the position specified by \a index. Returns (0, 0) if
713 the index is not valid.
714*/
715/*!
716 Returns the point at the position specified by \a index. Returns (0, 0) if
717 the index is not valid.
718*/
719QPointF QXYSeries::at(qsizetype index) const
720{
721 Q_D(const QXYSeries);
722 return d->m_points.at(i: index);
723}
724
725/*!
726 \qmlmethod int XYSeries::find(point point)
727 Finds and returns the index of the first matching point found as defined by \a point.
728 Returns -1 if the point is not found.
729*/
730/*!
731 Finds and returns the index of the first matching point found as defined by \a point.
732 Returns -1 if the point is not found.
733*/
734qsizetype QXYSeries::find(QPointF point) const
735{
736 Q_D(const QXYSeries);
737
738 for (qsizetype i = 0; i < d->m_points.size(); ++i) {
739 if (d->m_points[i] == point)
740 return i;
741 }
742
743 return -1;
744}
745
746QXYSeries::~QXYSeries() {}
747
748/*!
749 \property QXYSeries::color
750 \brief The main color of the series. For QLineSeries this means the line color and
751 for QScatterSeries the color of the point.
752*/
753/*!
754 \qmlproperty color XYSeries::color
755 The main color of the series. For LineSeries this means the line color and
756 for ScatterSeries the color of the point
757*/
758void QXYSeries::setColor(QColor newColor)
759{
760 Q_D(QXYSeries);
761 if (color() != newColor) {
762 d->m_color = newColor;
763 emit colorChanged(color: newColor);
764 } else {
765 qCDebug(lcProperties2D) << "QXYSeries::setColor. Color is already set to:"
766 << newColor;
767 }
768}
769
770QColor QXYSeries::color() const
771{
772 Q_D(const QXYSeries);
773 return d->m_color;
774}
775
776/*!
777 \property QXYSeries::selectedColor
778 \brief The color of selected points.
779*/
780/*!
781 \qmlproperty color XYSeries::selectedColor
782 The color of selected points.
783*/
784void QXYSeries::setSelectedColor(QColor color)
785{
786 Q_D(QXYSeries);
787 if (selectedColor() != color) {
788 d->m_selectedColor = color;
789 emit selectedColorChanged(color);
790 } else {
791 qCDebug(lcProperties2D) << "QXYSeries::setSelectedColor. Selected color is already set to:"
792 << color;
793 }
794}
795
796QColor QXYSeries::selectedColor() const
797{
798 Q_D(const QXYSeries);
799 return d->m_selectedColor;
800}
801
802/*!
803 \property QXYSeries::pointDelegate
804 \brief A custom QML Component used as a marker for data points.
805
806 The dynamic properties available for this component are:
807
808 \table
809 \header
810 \li Type
811 \li Name
812 \li Description
813 \row
814 \li bool
815 \li pointSelected
816 \li This value is true when the point is selected, meaning that the point index
817 is in \l{QXYSeries::selectedPoints}.
818 \row
819 \li QColor
820 \li pointColor
821 \li The color of the series. This value comes either from the \l QGraphsTheme
822 or from \l{QXYSeries::color} if the \l QXYSeries overrides the color.
823 \row
824 \li QColor
825 \li pointBorderColor
826 \li The border color of the series. This value comes from the \l QGraphsTheme.
827 \row
828 \li QColor
829 \li pointSelectedColor
830 \li The selected color of the series. This value comes either from the \l QGraphsTheme
831 or from \l{QXYSeries::selectedColor} if the \l QXYSeries overrides the color.
832 \row
833 \li qreal
834 \li pointBorderWidth
835 \li The border width of the series. This value comes from the \l QGraphsTheme.
836 \row
837 \li qreal
838 \li pointValueX
839 \li The value of the \l{QXYPoint::x} at this position.
840 \row
841 \li qreal
842 \li pointValueY
843 \li The value of the \l{QXYPoint::y} at this position.
844 \row
845 \li int
846 \li pointIndex
847 \li The index of the point, from 0 to the amount of points - 1. [since 6.9]
848 \endtable
849
850 To use any of these, add property with the defined name into your custom component.
851 For example \c{"property color pointColor"} and \c{"property real pointValueX"}.
852*/
853/*!
854 \qmlproperty Component XYSeries::pointDelegate
855 A custom QML Component used as a marker for data points.
856
857 The dynamic properties available for this component are:
858
859 \table
860 \header
861 \li Type
862 \li Name
863 \li Description
864 \row
865 \li bool
866 \li pointSelected
867 \li This value is true when the point is selected.
868 \row
869 \li Color
870 \li pointColor
871 \li The color of the series. This value comes either from the \l GraphsTheme
872 or from \l{XYSeries::color} if the \l XYSeries overrides the color.
873 \row
874 \li Color
875 \li pointBorderColor
876 \li The border color of the series. This value comes from the \l GraphsTheme.
877 \row
878 \li Color
879 \li pointSelectedColor
880 \li The selected color of the series. This value comes either from the \l GraphsTheme
881 or from \l{XYSeries::selectedColor} if the \l XYSeries overrides the color.
882 \row
883 \li real
884 \li pointBorderWidth
885 \li The border width of the series. This value comes from the \l GraphsTheme.
886 \row
887 \li real
888 \li pointValueX
889 \li The value of the \l{XYPoint::x} at this position.
890 \row
891 \li real
892 \li pointValueY
893 \li The value of the \l{XYPoint::y} at this position.
894 \row
895 \li int
896 \li pointIndex
897 \li The index of the point, from 0 to the amount of points - 1. [since 6.9]
898 \endtable
899
900 To use any of these, add property with the defined name into your custom component.
901 For example \c{"property color pointColor"} and \c{"property real pointValueX"}.
902*/
903QQmlComponent *QXYSeries::pointDelegate() const
904{
905 Q_D(const QXYSeries);
906 return d->m_pointDelegate;
907}
908
909void QXYSeries::setPointDelegate(QQmlComponent *newPointDelegate)
910{
911 Q_D(QXYSeries);
912 if (d->m_pointDelegate == newPointDelegate) {
913 qCDebug(lcProperties2D) << "QXYSeries::setPointDelegate. Point delegate is already set to:"
914 << newPointDelegate;
915 return;
916 }
917
918 d->m_pointDelegate = newPointDelegate;
919 emit pointDelegateChanged();
920 emit update();
921}
922
923/*!
924 \property QXYSeries::draggable
925 \brief Controls if the series is draggable.
926
927 Controls if the series can be dragged with mouse/touch.
928 By default, \a draggable is set to \c false.
929*/
930/*!
931 \qmlproperty bool QXYSeries::draggable
932 Controls if the series can be dragged with mouse/touch.
933 By default, \a draggable is set to \c false.
934*/
935bool QXYSeries::isDraggable() const
936{
937 Q_D(const QXYSeries);
938 return d->m_draggable;
939}
940
941void QXYSeries::setDraggable(bool newDraggable)
942{
943 Q_D(QXYSeries);
944 if (d->m_draggable == newDraggable) {
945 qCDebug(lcProperties2D) << "QXYSeries::setDraggable. Cannot set draggable, it is already set to:"
946 << newDraggable;
947 return;
948 }
949 d->m_draggable = newDraggable;
950 emit draggableChanged();
951}
952
953QXYSeries &QXYSeries::operator<<(QPointF point)
954{
955 append(point);
956 return *this;
957}
958
959QXYSeries &QXYSeries::operator<< (const QList<QPointF>& points)
960{
961 append(points);
962 return *this;
963}
964
965QXYSeriesPrivate::QXYSeriesPrivate(QAbstractSeries::SeriesType type)
966 : QAbstractSeriesPrivate(type)
967{}
968
969void QXYSeriesPrivate::setPointSelected(qsizetype index, bool selected, bool &callSignal)
970{
971 if (index < 0 || index > m_points.size() - 1) {
972 qCWarning(lcProperties2D, "tried to use invalid index: %" PRIdQSIZETYPE, index);
973 return;
974 }
975
976 if (selected) {
977 if (!isPointSelected(index)) {
978 m_selectedPoints << index;
979 callSignal = true;
980 }
981 } else {
982 if (isPointSelected(index)) {
983 m_selectedPoints.remove(value: index);
984 callSignal = true;
985 }
986 }
987}
988
989bool QXYSeriesPrivate::isPointSelected(qsizetype index) const
990{
991 return m_selectedPoints.contains(value: index);
992}
993
994void QXYSeriesPrivate::append(const QList<QPointF> &points)
995{
996 bool anim = m_graphTransition && m_graphTransition->initialized()
997 && m_graphTransition->contains(type: QGraphAnimation::GraphAnimationType::GraphPoint);
998
999 if (anim) {
1000 m_graphTransition->stop();
1001 qsizetype index = m_points.size();
1002
1003 for (auto point : points) {
1004 if (isValidValue(point)) {
1005 m_graphTransition->stop();
1006 m_graphTransition->onPointChanged(type: QGraphTransition::TransitionType::PointAdded,
1007 index,
1008 point);
1009 index++;
1010 }
1011 }
1012 } else {
1013 qsizetype start = m_points.size();
1014 m_points.append(l: points);
1015
1016 Q_Q(QXYSeries);
1017 Q_EMIT q->pointsAdded(start, end: m_points.size() - 1);
1018 Q_EMIT q->countChanged();
1019 }
1020}
1021
1022QT_END_NAMESPACE
1023

source code of qtgraphs/src/graphs2d/xychart/qxyseries.cpp