Source code

Revision control

Copy as Markdown

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "graphs2d/xychart/qxyseries.h"
#include "graphs2d/qabstractseries.h"
#include <QtGraphs/qxyseries.h>
#include <private/qxyseries_p.h>
#include <private/charthelpers_p.h>
#include <utility>
QT_BEGIN_NAMESPACE
/*!
\class QXYSeries
\inmodule QtGraphs
\ingroup graphs_2D
\brief The QXYSeries class is a parent class for all x & y series classes.
In QXYSeries, data points are defined as a list of QPointF, defining X and Y positions.
\sa QLineSeries, QScatterSeries
*/
/*!
\qmltype XYSeries
\nativetype QXYSeries
\inqmlmodule QtGraphs
\ingroup graphs_qml_2D
\inherits AbstractSeries
\brief A parent type for all x & y series types.
In XYSeries, data points are defined as a list of point types, defining X and Y positions.
*/
/*!
\fn void QXYSeries::pointReplaced(qsizetype index)
This signal is emitted when a point is replaced at the position specified by
\a index.
\sa replace()
*/
/*!
\qmlsignal XYSeries::pointReplaced(int index)
This signal is emitted when a point is replaced at the position specified by
\a index.
*/
/*!
\fn void QXYSeries::pointsReplaced()
This signal is emitted when all points are replaced.
*/
/*!
\qmlsignal XYSeries::pointsReplaced()
This signal is emitted when all points are replaced.
*/
/*!
\fn void QXYSeries::pointsAdded(qsizetype start, qsizetype end)
This signal is emitted when a list of points is appended.
The indexes of the new added points are between \a start and \a end.
\since 6.9
*/
/*!
\qmlsignal XYSeries::pointsAdded(int start, int end)
This signal is emitted when a list of points is appended.
The indexes of the new added points are between \a start and \a end.
\since 6.9
*/
/*!
\qmlsignal XYSeries::colorChanged(color color)
This signal is emitted when the line color changes to \a color.
*/
/*!
\qmlsignal XYSeries::selectedColorChanged(color color)
This signal is emitted when the color of selected series changes to \a color.
*/
/*!
\qmlsignal XYSeries::selectedPointsChanged()
This signal is emitted when the set of selected points changes.
*/
/*!
\qmlsignal XYSeries::pointMarkerChanged()
This signal is emitted when a point is changed.
*/
/*!
\qmlsignal XYSeries::draggableChanged()
This signal is emitted when a series becomes draggable by a mouse/touch or
becomes fixed.
*/
/*!
\qmlsignal XYSeries::clicked(point point)
This signal is emitted when the user clicks or taps the \a point in the graph.
*/
/*!
\qmlsignal XYSeries::doubleClicked(point point)
This signal is emitted when the user double-clicks or double-taps the data \a point in
the graph. The \a point is the point where the first press was triggered.
This signal always occurs after \l clicked.
*/
/*!
\qmlsignal XYSeries::pressed(point point)
This signal is emitted when the user presses the data \a point in the graph
and holds down the mouse button or gesture.
*/
/*!
\qmlsignal XYSeries::released(point point)
This signal is emitted when the user releases the previously pressed mouse
button or gesture on the data \a point.
*/
/*!
\qmlsignal XYSeries::hovered(bool state, point point)
This signal is emitted when the cursor moves close to the data \a point in the graph.
\a state is \c true when the cursor enters the vicinity of the point and \c false when
it leaves it.
*/
QXYSeries::QXYSeries(QXYSeriesPrivate &dd, QObject *parent)
: QAbstractSeries(dd, parent)
{
QObject::connect(this, &QXYSeries::selectedPointsChanged, this, &QAbstractSeries::update);
QObject::connect(this, &QXYSeries::pointAdded, this, &QAbstractSeries::update);
QObject::connect(this, &QXYSeries::pointsAdded, this, &QAbstractSeries::update);
QObject::connect(this, &QXYSeries::pointReplaced, this, &QAbstractSeries::update);
QObject::connect(this, &QXYSeries::pointsReplaced, this, &QAbstractSeries::update);
QObject::connect(this, &QXYSeries::pointRemoved, this, &QAbstractSeries::update);
QObject::connect(this, &QXYSeries::pointsRemoved, this, &QAbstractSeries::update);
}
/*!
\qmlmethod void XYSeries::append(real x, real y)
Appends a point with the coordinates \a x and \a y to the series.
*/
/*!
Appends a point with the coordinates \a x and \a y to the series.
*/
void QXYSeries::append(qreal x, qreal y)
{
append(QPointF(x, y));
}
/*!
\qmlmethod void XYSeries::append(point point)
Appends a point with the coordinates \a point to the series.
*/
/*!
Appends a point with the coordinates \a point to the series.
*/
void QXYSeries::append(QPointF point)
{
Q_D(QXYSeries);
if (d->m_graphTransition && d->m_graphTransition->initialized()
&& d->m_graphTransition->contains(QGraphAnimation::GraphAnimationType::GraphPoint)) {
d->m_graphTransition->stop();
if (isValidValue(point)) {
d->m_graphTransition->onPointChanged(QGraphTransition::TransitionType::PointAdded,
d->m_points.size(),
point);
}
} else {
d->m_points << point;
emit pointAdded(d->m_points.size() - 1);
emit countChanged();
}
}
/*!
\qmlmethod void XYSeries::append(list<point> points)
Appends points with the coordinates \a points to the series.
\note This is much faster than appending data points one by one.
Emits \l pointsAdded when the points have been added.
*/
/*!
Appends points with the coordinates \a points to the series.
\note This is much faster than appending data points one by one.
Emits \l pointsAdded when the points have been added.
*/
void QXYSeries::append(const QList<QPointF> &points)
{
Q_D(QXYSeries);
d->append(points);
}
/*!
\qmlmethod void XYSeries::replace(real oldX, real oldY, real newX, real newY)
Replaces the point with the coordinates \a oldX and \a oldY with the point
with the coordinates \a newX and \a newY. Does nothing if the old point does
not exist.
*/
/*!
Replaces the point with the coordinates \a oldX and \a oldY with the point
with the coordinates \a newX and \a newY. Does nothing if the old point does
not exist.
*/
void QXYSeries::replace(qreal oldX, qreal oldY, qreal newX, qreal newY)
{
replace(QPointF(oldX, oldY), QPointF(newX, newY));
}
/*!
\qmlmethod void XYSeries::replace(point oldPoint, point newPoint)
Replaces the point with the coordinates \a oldPoint with the point
with the coordinates \a newPoint. Does nothing if the old point does
not exist.
*/
/*!
Replaces the point with the coordinates \a oldPoint with the point
with the coordinates \a newPoint. Does nothing if the old point does
not exist.
*/
void QXYSeries::replace(QPointF oldPoint, QPointF newPoint)
{
Q_D(QXYSeries);
qsizetype index = d->m_points.indexOf(oldPoint);
if (index == -1)
return;
replace(index, newPoint);
}
/*!
\qmlmethod void XYSeries::replace(int index, real newX, real newY)
Replaces the point at the position specified by \a index with the point
that has the coordinates \a newX and \a newY.
*/
/*!
Replaces the point at the position specified by \a index with the point
that has the coordinates \a newX and \a newY.
*/
void QXYSeries::replace(qsizetype index, qreal newX, qreal newY)
{
replace(index, QPointF(newX, newY));
}
/*!
\qmlmethod void XYSeries::replace(int index, point newPoint)
Replaces the point at the position specified by \a index with the point
that has the coordinates \a newPoint.
*/
/*!
Replaces the point at the position specified by \a index with the point
that has the coordinates \a newPoint.
*/
void QXYSeries::replace(qsizetype index, QPointF newPoint)
{
Q_D(QXYSeries);
if (index < 0 || index >= d->m_points.size())
return;
if (d->m_graphTransition && d->m_graphTransition->initialized()
&& d->m_graphTransition->contains(QGraphAnimation::GraphAnimationType::GraphPoint)) {
d->m_graphTransition->stop();
if (isValidValue(newPoint)) {
d->m_graphTransition->onPointChanged(QGraphTransition::TransitionType::PointReplaced,
index,
newPoint);
}
} else {
d->m_points[index] = newPoint;
emit pointReplaced(index);
}
}
/*!
\qmlmethod void XYSeries::replace(list<point> points)
Replaces the current points with the points specified by \a points
\note This is much faster than replacing data points one by one, or first
clearing all data, and then appending the new data. Emits \l pointsReplaced
when the points have been replaced.
*/
/*!
Replaces the current points with the points specified by \a points
\note This is much faster than replacing data points one by one, or first
clearing all data, and then appending the new data. Emits \l pointsReplaced
when the points have been replaced.
*/
void QXYSeries::replace(const QList<QPointF> &points)
{
Q_D(QXYSeries);
bool hasDifferentSize = d->m_points.size() != points.size();
d->m_points = points;
emit pointsReplaced();
if (hasDifferentSize)
emit countChanged();
}
/*!
\qmlmethod void XYSeries::remove(real x, real y)
Removes the point with the coordinates \a x and \a y from the series. Does
nothing if the point does not exist.
*/
/*!
Removes the point with the coordinates \a x and \a y from the series. Does
nothing if the point does not exist.
*/
void QXYSeries::remove(qreal x, qreal y)
{
remove(QPointF(x, y));
}
/*!
\qmlmethod void XYSeries::remove(point point)
Removes the point with the coordinates \a point from the series. Does
nothing if the point does not exist.
*/
/*!
Removes the point with the coordinates \a point from the series. Does
nothing if the point does not exist.
*/
void QXYSeries::remove(QPointF point)
{
Q_D(QXYSeries);
qsizetype index = d->m_points.indexOf(point);
if (index == -1)
return;
remove(index);
}
/*!
\qmlmethod void XYSeries::remove(int index)
Removes the point at the position specified by \a index from the series.
*/
/*!
Removes the point at the position specified by \a index from the series.
*/
void QXYSeries::remove(qsizetype index)
{
Q_D(QXYSeries);
if (index < 0 || index >= d->m_points.size())
return;
if (d->m_graphTransition && d->m_graphTransition->initialized()
&& d->m_graphTransition->contains(QGraphAnimation::GraphAnimationType::GraphPoint)) {
d->m_graphTransition->stop();
d->m_graphTransition->onPointChanged(QGraphTransition::TransitionType::PointRemoved,
index,
{});
} else {
d->m_points.remove(index);
bool callSignal = false;
d->setPointSelected(index, false, callSignal);
emit pointRemoved(index);
emit countChanged();
if (callSignal)
emit selectedPointsChanged();
}
}
/*!
\qmlmethod void XYSeries::removeMultiple(int index, int count)
Removes the number of points specified by \a count from the series starting
at the position specified by \a index.
*/
/*!
Removes the number of points specified by \a count from the series starting
at the position specified by \a index.
*/
void QXYSeries::removeMultiple(qsizetype index, qsizetype count)
{
// This function doesn't overload remove as there is chance for it to get mixed up with
// remove(qreal, qreal) overload in some implicit casting cases.
Q_D(QXYSeries);
if (index < 0 || count < 1 || index + count > d->m_points.size())
return;
if (count > 0) {
if (d->m_graphTransition && d->m_graphTransition->initialized()
&& d->m_graphTransition->contains(QGraphAnimation::GraphAnimationType::GraphPoint)) {
d->m_graphTransition->stop();
}
d->m_points.remove(index, count);
bool callSignal = false;
if (!d->m_selectedPoints.empty()) {
QSet<qsizetype> selectedAfterRemoving;
for (const qsizetype &selectedPointIndex : std::as_const(d->m_selectedPoints)) {
if (selectedPointIndex < index) {
selectedAfterRemoving << selectedPointIndex;
} else if (selectedPointIndex >= index + count) {
selectedAfterRemoving << selectedPointIndex - int(count);
callSignal = true;
} else {
callSignal = true;
}
}
d->m_selectedPoints = selectedAfterRemoving;
}
emit pointsRemoved(index, count);
emit countChanged();
if (callSignal)
emit selectedPointsChanged();
}
}
/*!
\qmlmethod bool XYSeries::take(point point)
Takes a point, specified by \a point, out of the series if found. Returns \c true if
the operation is successful.
*/
/*!
Takes a point, specified by \a point, out of the series if found. Returns \c true if
the operation is successful.
*/
bool QXYSeries::take(QPointF point)
{
Q_D(QXYSeries);
for (int i = 0; i < d->m_points.size(); ++i) {
if (d->m_points[i] == point) {
d->m_points.removeAt(i);
return true;
}
}
return false;
}
/*!
\qmlmethod void XYSeries::insert(int index, point point)
Inserts a point with the coordinates \a point to the position specified
by \a index in the series. If the index is 0 or less than 0, the point is
prepended to the list of points. If the index is equal to or greater than
than the number of points in the series, the point is appended to the
list of points.
*/
/*!
Inserts a point with the coordinates \a point to the position specified
by \a index in the series. If the index is 0 or less than 0, the point is
prepended to the list of points. If the index is equal to or greater than
than the number of points in the series, the point is appended to the
list of points.
*/
void QXYSeries::insert(qsizetype index, QPointF point)
{
Q_D(QXYSeries);
index = qMax(0, qMin(index, d->m_points.size()));
d->m_points.insert(index, point);
bool callSignal = false;
if (!d->m_selectedPoints.isEmpty()) {
// if point was inserted we need to move already selected points by 1
QSet<qsizetype> selectedAfterInsert;
for (const auto &value : std::as_const(d->m_selectedPoints)) {
if (value >= index) {
selectedAfterInsert << value + 1;
callSignal = true;
} else {
selectedAfterInsert << value;
}
}
d->m_selectedPoints = selectedAfterInsert;
}
emit pointAdded(index);
if (callSignal)
emit selectedPointsChanged();
}
/*!
\qmlmethod void XYSeries::clear()
Removes all points from the series.
*/
/*!
Removes all points from the series.
*/
void QXYSeries::clear()
{
Q_D(QXYSeries);
removeMultiple(0, d->m_points.size());
}
/*!
\qmlmethod bool XYSeries::isPointSelected(int index)
Returns true if point at given \a index is among selected points and false otherwise.
\note Selected points are drawn using the selected color if it was specified.
\sa selectedPoints, setPointSelected(), selectedColor
*/
/*!
Returns true if point at given \a index is among selected points and false otherwise.
\note Selected points are drawn using the selected color if it was specified.
\sa selectedPoints, setPointSelected(), setSelectedColor()
*/
bool QXYSeries::isPointSelected(qsizetype index) const
{
Q_D(const QXYSeries);
return d->isPointSelected(index);
}
/*!
\qmlmethod void XYSeries::selectPoint(int index)
Marks point at \a index as selected.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
/*!
Marks point at \a index as selected.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
void QXYSeries::selectPoint(qsizetype index)
{
setPointSelected(index, true);
}
/*!
\qmlmethod void XYSeries::deselectPoint(int index)
Deselects point at given \a index.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
/*!
Deselects point at given \a index.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
void QXYSeries::deselectPoint(qsizetype index)
{
setPointSelected(index, false);
}
/*!
\qmlmethod void XYSeries::setPointSelected(int index, bool selected)
Marks point at given \a index as either selected or deselected as specified by \a selected.
\note Selected points are drawn using the selected color if it was specified. Emits QXYSeries::selectedPointsChanged
\sa selectAllPoints(), selectedColor
*/
/*!
Marks point at given \a index as either selected or deselected as specified by \a selected.
\note Selected points are drawn using the selected color if it was specified. Emits QXYSeries::selectedPointsChanged
\sa selectAllPoints(), setSelectedColor()
*/
void QXYSeries::setPointSelected(qsizetype index, bool selected)
{
Q_D(QXYSeries);
bool callSignal = false;
d->setPointSelected(index, selected, callSignal);
if (callSignal)
emit selectedPointsChanged();
}
/*!
\qmlmethod void XYSeries::selectAllPoints()
Marks all points in the series as selected,
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
/*!
Marks all points in the series as selected,
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
void QXYSeries::selectAllPoints()
{
Q_D(QXYSeries);
bool callSignal = false;
for (int i = 0; i < d->m_points.size(); ++i)
d->setPointSelected(i, true, callSignal);
if (callSignal)
emit selectedPointsChanged();
}
/*!
\qmlmethod void XYSeries::deselectAllPoints()
Deselects all points in the series.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
/*!
Deselects all points in the series.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
void QXYSeries::deselectAllPoints()
{
Q_D(QXYSeries);
bool callSignal = false;
for (int i = 0; i < d->m_points.size(); ++i)
d->setPointSelected(i, false, callSignal);
if (callSignal)
emit selectedPointsChanged();
}
/*!
\qmlmethod void XYSeries::selectPoints(list<int> indexes)
Marks multiple points passed in a \a indexes list as selected.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
/*!
Marks multiple points passed in a \a indexes list as selected.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
void QXYSeries::selectPoints(const QList<qsizetype> &indexes)
{
Q_D(QXYSeries);
bool callSignal = false;
for (const qsizetype &index : indexes)
d->setPointSelected(index, true, callSignal);
if (callSignal)
emit selectedPointsChanged();
}
/*!
\qmlmethod void XYSeries::deselectPoints(list<int> indexes)
Marks multiple points passed in a \a indexes list as deselected.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
/*!
Marks multiple points passed in a \a indexes list as deselected.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
void QXYSeries::deselectPoints(const QList<qsizetype> &indexes)
{
Q_D(QXYSeries);
bool callSignal = false;
for (const qsizetype &index : indexes)
d->setPointSelected(index, false, callSignal);
if (callSignal)
emit selectedPointsChanged();
}
/*!
\qmlmethod void XYSeries::toggleSelection(list<int> indexes)
Changes selection state of points at given \a indexes to the opposite one.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
/*!
Changes selection state of points at given \a indexes to the opposite one.
\note Emits QXYSeries::selectedPointsChanged
\sa setPointSelected()
*/
void QXYSeries::toggleSelection(const QList<qsizetype> &indexes)
{
Q_D(QXYSeries);
bool callSignal = false;
for (const qsizetype &index : indexes)
d->setPointSelected(index, !isPointSelected(index), callSignal);
if (callSignal)
emit selectedPointsChanged();
}
/*!
\property QXYSeries::selectedPoints
\brief The indexes of the points which are currently selected.
*/
/*!
\qmlproperty list<int> XYSeries::selectedPoints
The indexes of the points which are currently selected.
*/
/*!
Returns a list of points indexes marked as selected.
Selected points are visible regardless of points visibility.
\sa setPointSelected()
*/
QList<qsizetype> QXYSeries::selectedPoints() const
{
Q_D(const QXYSeries);
return QList<qsizetype>(d->m_selectedPoints.begin(), d->m_selectedPoints.end());
}
/*!
\property QXYSeries::count
\brief Returns the number of data points in a series.
*/
/*!
\qmlproperty int XYSeries::count
Returns the number of data points in a series.
*/
qsizetype QXYSeries::count() const
{
Q_D(const QXYSeries);
return d->m_points.size();
}
/*!
\property QXYSeries::values
\since 6.12
\brief The points of the series, set declaratively.
The variant list can contain either \l QPointF values or numbers.
If numbers are given, \l{valueMapping} controls
whether each number is interpreted as an X or Y component.
\sa valueMapping, valueMin, stepSize
*/
/*!
\qmlproperty list<variant> XYSeries::values
\since 6.12
This property can be used to set points declaratively for a XYSeries.
The variant list can be either points or numbers. If numbers are given,
the \l{QXYSeries::valueMapping}{valueMapping} can be used to indicate whether
the number is interpreted as the X or Y component of a point.
*/
QVariantList QXYSeries::values() const
{
Q_D(const QXYSeries);
return d->m_values;
}
void QXYSeries::setValues(QVariantList values)
{
Q_D(QXYSeries);
if (!values.isSharedWith(d->m_values)) {
d->m_values = values;
if (!d->m_values.isEmpty()) {
QList<QPointF> temp;
if (values.at(0).canConvert<QPointF>())
temp = d->pointsFromPoints();
else
temp = d->pointsFromNumbers(d->m_valueMapping);
replace(temp);
} else {
clear();
}
emit valuesChanged(d->m_values);
} else {
qCDebug(lcProperties2D) << "QXYSeries::setValues. Values are already set to:" << values;
}
}
/*!
\enum QXYSeries::ValueMapping
\since 6.12
This enum describes how plain numbers in \l values are interpreted.
\value X Each number is the X value; Y is generated from the index
and \l stepSize.
\value Y Each number is the Y value; X is generated from \l valueMin
and \l stepSize.
*/
/*!
\property QXYSeries::valueMapping
\since 6.12
\brief Controls how numbers in \l values are interpreted.
When \l values contains plain numbers rather than \l QPointF
values, this property determines whether each number is the X or Y component
of a point.
\sa values, valueMin, stepSize
*/
QXYSeries::ValueMapping QXYSeries::valueMapping() const
{
Q_D(const QXYSeries);
return d->m_valueMapping;
}
void QXYSeries::setValueMapping(ValueMapping newHint)
{
Q_D(QXYSeries);
if (newHint == d->m_valueMapping) {
qCDebug(lcProperties2D) << "QXYSeries::setValueMapping. Value mapping is already set to:"
<< newHint;
return;
}
d->m_valueMapping = newHint;
if (d->m_values.size() && d->m_values[0].canConvert<float>())
replace(d->pointsFromNumbers(d->m_valueMapping));
emit valueMappingChanged(newHint);
}
/*!
\property QXYSeries::valueMin
\since 6.12
\brief The minimum X (or Y) value used when generating points from
plain numbers in \l values.
Used together with \l stepSize when \l valueMapping is
\c ValueMapping::Y to generate the X values for each point.
The default value is 0.
\sa values, valueMapping, stepSize
*/
qreal QXYSeries::valueMin() const
{
Q_D(const QXYSeries);
return d->m_valueMin;
}
void QXYSeries::setValueMin(qreal newMin)
{
Q_D(QXYSeries);
if (qFuzzyCompare(newMin, d->m_valueMin)) {
qCDebug(lcProperties2D) << "QXYSeries::setValueMin. Value min is already set to:"
<< newMin;
return;
}
d->m_valueMin = newMin;
if (d->m_values.size() && d->m_values[0].canConvert<float>())
replace(d->pointsFromNumbers(d->m_valueMapping));
emit valueMinChanged(newMin);
}
/*!
\property QXYSeries::stepSize
\since 6.12
\brief The step size between auto-generated X (or Y) values when
populating the series from plain numbers via \l values.
The default value is 1.
\sa values, valueMapping, valueMin
*/
qreal QXYSeries::stepSize() const
{
Q_D(const QXYSeries);
return d->m_stepSize;
}
void QXYSeries::setStepSize(qreal newStepSize)
{
Q_D(QXYSeries);
if (qFuzzyCompare(newStepSize, d->m_stepSize)) {
qCDebug(lcProperties2D) << "QXYSeries::setStepSize. Step size is already set to:"
<< newStepSize;
return;
}
d->m_stepSize = newStepSize;
if (d->m_values.size() && d->m_values[0].canConvert<float>())
replace(d->pointsFromNumbers(d->m_valueMapping));
emit stepSizeChanged(newStepSize);
}
/*!
Returns the points in the series.
*/
QList<QPointF> QXYSeries::points() const
{
Q_D(const QXYSeries);
return d->m_points;
}
/*!
\qmlmethod point XYSeries::at(int index)
Returns the point at the position specified by \a index. Returns (0, 0) if
the index is not valid.
*/
/*!
Returns the point at the position specified by \a index. Returns (0, 0) if
the index is not valid.
*/
QPointF QXYSeries::at(qsizetype index) const
{
Q_D(const QXYSeries);
return d->m_points.at(index);
}
/*!
\qmlmethod int XYSeries::find(point point)
Finds and returns the index of the first matching point found as defined by \a point.
Returns -1 if the point is not found.
*/
/*!
Finds and returns the index of the first matching point found as defined by \a point.
Returns -1 if the point is not found.
*/
qsizetype QXYSeries::find(QPointF point) const
{
Q_D(const QXYSeries);
for (qsizetype i = 0; i < d->m_points.size(); ++i) {
if (d->m_points[i] == point)
return i;
}
return -1;
}
QXYSeries::~QXYSeries() {}
/*!
\property QXYSeries::color
\brief The main color of the series. For QLineSeries this means the line color and
for QScatterSeries the color of the point.
*/
/*!
\qmlproperty color XYSeries::color
The main color of the series. For LineSeries this means the line color and
for ScatterSeries the color of the point
*/
void QXYSeries::setColor(QColor newColor)
{
Q_D(QXYSeries);
if (color() != newColor) {
d->m_color = newColor;
emit colorChanged(newColor);
} else {
qCDebug(lcProperties2D) << "QXYSeries::setColor. Color is already set to:"
<< newColor;
}
}
QColor QXYSeries::color() const
{
Q_D(const QXYSeries);
return d->m_color;
}
/*!
\property QXYSeries::selectedColor
\brief The color of selected points.
*/
/*!
\qmlproperty color XYSeries::selectedColor
The color of selected points.
*/
void QXYSeries::setSelectedColor(QColor color)
{
Q_D(QXYSeries);
if (selectedColor() != color) {
d->m_selectedColor = color;
emit selectedColorChanged(color);
} else {
qCDebug(lcProperties2D) << "QXYSeries::setSelectedColor. Selected color is already set to:"
<< color;
}
}
QColor QXYSeries::selectedColor() const
{
Q_D(const QXYSeries);
return d->m_selectedColor;
}
/*!
\property QXYSeries::pointDelegate
\brief A custom QML Component used as a marker for data points.
The dynamic properties available for this component are:
\table
\header
\li Type
\li Name
\li Description
\row
\li bool
\li pointSelected
\li This value is true when the point is selected, meaning that the point index
is in \l{QXYSeries::selectedPoints}.
\row
\li QColor
\li pointColor
\li The color of the series. This value comes either from the \l QGraphsTheme
or from \l{QXYSeries::color} if the \l QXYSeries overrides the color.
\row
\li QColor
\li pointBorderColor
\li The border color of the series. This value comes from the \l QGraphsTheme.
\row
\li QColor
\li pointSelectedColor
\li The selected color of the series. This value comes either from the \l QGraphsTheme
or from \l{QXYSeries::selectedColor} if the \l QXYSeries overrides the color.
\row
\li qreal
\li pointBorderWidth
\li The border width of the series. This value comes from the \l QGraphsTheme.
\row
\li qreal
\li pointValueX
\li The value of the \l{QXYPoint::x} at this position.
\row
\li qreal
\li pointValueY
\li The value of the \l{QXYPoint::y} at this position.
\row
\li int
\li pointIndex
\li The index of the point, from 0 to the amount of points - 1. [since 6.9]
\endtable
To use any of these, add property with the defined name into your custom component.
For example \c{"property color pointColor"} and \c{"property real pointValueX"}.
*/
/*!
\qmlproperty Component XYSeries::pointDelegate
A custom QML Component used as a marker for data points.
The dynamic properties available for this component are:
\table
\header
\li Type
\li Name
\li Description
\row
\li bool
\li pointSelected
\li This value is true when the point is selected.
\row
\li Color
\li pointColor
\li The color of the series. This value comes either from the \l GraphsTheme
or from \l{XYSeries::color} if the \l XYSeries overrides the color.
\row
\li Color
\li pointBorderColor
\li The border color of the series. This value comes from the \l GraphsTheme.
\row
\li Color
\li pointSelectedColor
\li The selected color of the series. This value comes either from the \l GraphsTheme
or from \l{XYSeries::selectedColor} if the \l XYSeries overrides the color.
\row
\li real
\li pointBorderWidth
\li The border width of the series. This value comes from the \l GraphsTheme.
\row
\li real
\li pointValueX
\li The value of the \l{XYPoint::x} at this position.
\row
\li real
\li pointValueY
\li The value of the \l{XYPoint::y} at this position.
\row
\li int
\li pointIndex
\li The index of the point, from 0 to the amount of points - 1. [since 6.9]
\endtable
To use any of these, add property with the defined name into your custom component.
For example \c{"property color pointColor"} and \c{"property real pointValueX"}.
*/
QQmlComponent *QXYSeries::pointDelegate() const
{
Q_D(const QXYSeries);
return d->m_pointDelegate;
}
void QXYSeries::setPointDelegate(QQmlComponent *newPointDelegate)
{
Q_D(QXYSeries);
if (d->m_pointDelegate == newPointDelegate) {
qCDebug(lcProperties2D) << "QXYSeries::setPointDelegate. Point delegate is already set to:"
<< newPointDelegate;
return;
}
d->m_pointDelegate = newPointDelegate;
emit pointDelegateChanged();
emit update();
}
/*!
\property QXYSeries::draggable
\brief Controls if the series is draggable.
Controls if the series can be dragged with mouse/touch.
By default, \a draggable is set to \c false.
*/
/*!
\qmlproperty bool XYSeries::draggable
Controls if the series can be dragged with mouse/touch.
By default, \a draggable is set to \c false.
*/
bool QXYSeries::isDraggable() const
{
Q_D(const QXYSeries);
return d->m_draggable;
}
void QXYSeries::setDraggable(bool newDraggable)
{
Q_D(QXYSeries);
if (d->m_draggable == newDraggable) {
qCDebug(lcProperties2D) << "QXYSeries::setDraggable. Cannot set draggable, it is already set to:"
<< newDraggable;
return;
}
d->m_draggable = newDraggable;
emit draggableChanged();
}
QXYSeries &QXYSeries::operator<<(QPointF point)
{
append(point);
return *this;
}
QXYSeries &QXYSeries::operator<< (const QList<QPointF>& points)
{
append(points);
return *this;
}
QXYSeriesPrivate::QXYSeriesPrivate(QAbstractSeries::SeriesType type)
: QAbstractSeriesPrivate(type)
{}
void QXYSeriesPrivate::setPointSelected(qsizetype index, bool selected, bool &callSignal)
{
if (index < 0 || index > m_points.size() - 1) {
qCWarning(lcProperties2D, "tried to use invalid index: %" PRIdQSIZETYPE, index);
return;
}
if (selected) {
if (!isPointSelected(index)) {
m_selectedPoints << index;
callSignal = true;
}
} else {
if (isPointSelected(index)) {
m_selectedPoints.remove(index);
callSignal = true;
}
}
}
bool QXYSeriesPrivate::isPointSelected(qsizetype index) const
{
return m_selectedPoints.contains(index);
}
void QXYSeriesPrivate::append(const QList<QPointF> &points)
{
bool anim = m_graphTransition && m_graphTransition->initialized()
&& m_graphTransition->contains(QGraphAnimation::GraphAnimationType::GraphPoint);
if (anim) {
m_graphTransition->stop();
qsizetype index = m_points.size();
for (auto point : points) {
if (isValidValue(point)) {
m_graphTransition->stop();
m_graphTransition->onPointChanged(QGraphTransition::TransitionType::PointAdded,
index,
point);
index++;
}
}
} else {
qsizetype start = m_points.size();
m_points.append(points);
Q_Q(QXYSeries);
Q_EMIT q->pointsAdded(start, m_points.size() - 1);
Q_EMIT q->countChanged();
}
}
QList<QPointF> QXYSeriesPrivate::pointsFromNumbers(QXYSeries::ValueMapping hint)
{
float other = m_valueMin;
QList<QPointF> temp;
temp.reserve(m_values.size());
if (hint == QXYSeries::ValueMapping::Y) {
for (const auto &i : std::as_const(m_values)) {
temp.append(QPointF(other, i.toFloat()));
other += m_stepSize;
}
} else if (hint == QXYSeries::ValueMapping::X) {
for (const auto &i : std::as_const(m_values)) {
temp.append(QPointF(i.toFloat(), other));
other += m_stepSize;
}
}
return temp;
}
QList<QPointF> QXYSeriesPrivate::pointsFromPoints()
{
QList<QPointF> temp;
temp.reserve(m_values.size());
for (const auto &i : std::as_const(m_values))
temp.append(i.toPointF());
return temp;
}
QT_END_NAMESPACE
#include "moc_qxyseries.cpp"