28#include <QDomDocument>
33#include "moc_qgslayoutitemchart.cpp"
35using namespace Qt::StringLiterals;
45 mGathererTimer.setInterval( 10 );
46 mGathererTimer.setSingleShot(
true );
47 connect( &mGathererTimer, &QTimer::timeout,
this, &QgsLayoutItemChart::gatherData );
75 bool requireRefresh = !mPlot || !
plot;
78 if ( mPlot->type() !=
plot->type() )
80 requireRefresh =
true;
86 if ( oldPlot2dXy && newPlot2dXy && oldPlot2dXy->
xAxis().
type() == newPlot2dXy->
xAxis().
type() )
89 requireRefresh =
false;
93 requireRefresh =
true;
98 mPlot.reset( plot2d );
109 if ( layer == mVectorLayer.get() )
114 mVectorLayer.setLayer( layer );
123 if ( mSortFeatures == sorted )
128 mSortFeatures = sorted;
136 if ( mSortAscending == ascending )
141 mSortAscending = ascending;
149 if ( mSortExpression == expression )
154 mSortExpression = expression;
185 if ( mFilterOnlyVisibleFeatures == visibleOnly )
190 mFilterOnlyVisibleFeatures = visibleOnly;
198 if ( mFilterToAtlasIntersection == filterToAtlas )
203 mFilterToAtlasIntersection = filterToAtlas;
228 if ( !
mLayout || !painter || !painter->device() )
241 QPaintDevice *paintDevice = painter->device();
245 QRectF thisPaintRect = rect();
249 if (
mLayout->renderContext().isPreviewRender() )
251 if ( mNeedsGathering || mIsGathering )
253 if ( mNeedsGathering )
255 mNeedsGathering =
false;
260 painter->setClipRect( thisPaintRect );
262 painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
263 painter->drawRect( thisPaintRect );
264 painter->setBrush( Qt::NoBrush );
266 messageFont.setPointSize( 12 );
267 painter->setFont( messageFont );
268 painter->setPen( QColor( 255, 255, 255, 255 ) );
269 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr(
"Rendering chart" ) );
275 if ( mNeedsGathering )
277 mNeedsGathering =
false;
282 mGatherer->waitForFinished( 60000 );
289 if ( size.width() == 0 || size.height() == 0 )
292 mPlot->setSize( size );
296 painter->scale( 1 / scaleFactor, 1 / scaleFactor );
303 mPlot->render( renderContext, plotRenderContext, mPlotData );
306 if ( mSeriesList.isEmpty() )
309 messageFont.setPointSize( 8 );
310 painter->setFont( messageFont );
311 painter->setPen( QColor( 125, 125, 125, 125 ) );
312 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr(
"Missing chart data" ) );
319 if ( mVectorLayer && !mSeriesList.isEmpty() )
321 mNeedsGathering =
true;
325void QgsLayoutItemChart::refreshData()
327 mGathererTimer.start();
330void QgsLayoutItemChart::gatherData()
342void QgsLayoutItemChart::prepareGatherer()
351 if ( !mVectorLayer || !mPlot || mSeriesList.isEmpty() )
353 mPlotData.clearSeries();
354 mIsGathering =
false;
361 mPlotData.clearSeries();
362 mIsGathering =
false;
375 mPlotData.clearSeries();
376 mIsGathering =
false;
380 if ( QgsVectorLayerXyPlotDataGatherer *xyGatherer =
dynamic_cast<QgsVectorLayerXyPlotDataGatherer *
>( mGatherer.data() ) )
382 QList<QgsVectorLayerXyPlotDataGatherer::XySeriesDetails> xYSeriesList;
385 xYSeriesList << QgsVectorLayerXyPlotDataGatherer::XySeriesDetails( series.name(), series.xExpression(), series.yExpression(), series.filterExpression() );
388 QgsFeatureRequest request;
389 QStringList filterExpressions;
390 for ( QgsLayoutItemChart::SeriesDetails &series : mSeriesList )
392 if ( !series.filterExpression().isEmpty() )
394 filterExpressions << series.filterExpression();
397 if ( !filterExpressions.isEmpty() )
402 if ( mSortFeatures && !mSortExpression.isEmpty() )
404 request.
addOrderBy( mSortExpression, mSortAscending );
407 if ( mFilterToAtlasIntersection )
409 const QgsGeometry atlasGeometry =
mLayout->reportContext().currentGeometry( mVectorLayer->crs() );
410 if ( !atlasGeometry.
isNull() )
415 else if ( mMap && mFilterOnlyVisibleFeatures )
418 if ( mVectorLayer->crs() != mMap->crs() )
420 const QgsCoordinateTransform transform( mVectorLayer->crs(), mMap->crs(),
mLayout->project() );
421 if ( visibleRegionGeometry.
transform( transform ) != Qgis::GeometryOperationResult ::Success )
423 visibleRegionGeometry = QgsGeometry();
426 if ( !visibleRegionGeometry.
isNull() )
433 QgsFeatureIterator featureIterator = mVectorLayer->getFeatures( request );
435 xyGatherer->setFeatureIterator( featureIterator );
437 xyGatherer->setSeriesDetails( xYSeriesList );
443void QgsLayoutItemChart::processData()
445 mPlotData = mGatherer->data();
448 mIsGathering =
false;
456 QDomElement plotElement = document.createElement( u
"plot"_s );
457 mPlot->writeXml( plotElement, document, context );
458 element.appendChild( plotElement );
461 QDomElement seriesListElement = document.createElement( u
"seriesList"_s );
464 QDomElement seriesElement = document.createElement( u
"series"_s );
465 seriesElement.setAttribute( u
"name"_s, series.name() );
466 seriesElement.setAttribute( u
"xExpression"_s, series.xExpression() );
467 seriesElement.setAttribute( u
"yExpression"_s, series.yExpression() );
468 seriesElement.setAttribute( u
"filterExpression"_s, series.filterExpression() );
469 seriesListElement.appendChild( seriesElement );
471 element.appendChild( seriesListElement );
475 element.setAttribute( u
"vectorLayer"_s, mVectorLayer.layerId );
476 element.setAttribute( u
"vectorLayerName"_s, mVectorLayer.name );
477 element.setAttribute( u
"vectorLayerSource"_s, mVectorLayer.source );
478 element.setAttribute( u
"vectorLayerProvider"_s, mVectorLayer.provider );
481 element.setAttribute( u
"sortFeatures"_s, mSortFeatures ? u
"1"_s : u
"0"_s );
482 element.setAttribute( u
"sortAscending"_s, mSortAscending ? u
"1"_s : u
"0"_s );
483 element.setAttribute( u
"sortExpression"_s, mSortExpression );
485 element.setAttribute( u
"sortExpression"_s, mSortExpression );
487 element.setAttribute( u
"filterOnlyVisibleFeatures"_s, mFilterOnlyVisibleFeatures );
488 element.setAttribute( u
"filterToAtlasIntersection"_s, mFilterToAtlasIntersection );
492 element.setAttribute( u
"mapUuid"_s, mMap->uuid() );
500 QDomElement plotElement = element.firstChildElement( u
"plot"_s );
501 if ( !plotElement.isNull() )
506 mPlot->readXml( plotElement, context );
511 const QDomNodeList seriesNodeList = element.firstChildElement( u
"seriesList"_s ).childNodes();
512 for (
int i = 0; i < seriesNodeList.count(); i++ )
514 const QDomElement seriesElement = seriesNodeList.at( i ).toElement();
516 series.
setXExpression( seriesElement.attribute(
"xExpression" ) );
517 series.
setYExpression( seriesElement.attribute(
"yExpression" ) );
519 mSeriesList << series;
522 QString layerId = element.attribute( u
"vectorLayer"_s );
523 QString layerName = element.attribute( u
"vectorLayerName"_s );
524 QString layerSource = element.attribute( u
"vectorLayerSource"_s );
525 QString layerProvider = element.attribute( u
"vectorLayerProvider"_s );
526 mVectorLayer =
QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
527 mVectorLayer.resolveWeakly(
mLayout->project() );
529 mSortFeatures = element.attribute( u
"sortFeatures"_s, u
"0"_s ).toInt();
530 mSortAscending = element.attribute( u
"sortAscending"_s, u
"1"_s ).toInt();
531 mSortExpression = element.attribute( u
"sortExpression"_s );
533 mFilterOnlyVisibleFeatures = element.attribute( u
"filterOnlyVisibleFeatures"_s, u
"1"_s ).toInt();
534 mFilterToAtlasIntersection = element.attribute( u
"filterToAtlasIntersection"_s, u
"0"_s ).toInt();
536 mMapUuid = element.attribute( u
"mapUuid"_s );
544 mNeedsGathering =
true;
551 if ( !mMap && !mMapUuid.isEmpty() &&
mLayout )
553 mMap = qobject_cast< QgsLayoutItemMap *>(
mLayout->itemByUuid( mMapUuid,
true ) );
Base class for 2-dimensional plot/chart/graphs.
Base class for 2-dimensional plot/chart/graphs with an X and Y axes.
QgsPlotAxis & xAxis()
Returns a reference to the plot's x axis.
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
static QgsPlotRegistry * plotRegistry()
Returns the application's plot registry, used for plot types.
QgsFeatureRequest & addOrderBy(const QString &expression, bool ascending=true)
Adds a new OrderByClause, appending it as the least important one.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
QgsFeatureRequest & setDistanceWithin(const QgsGeometry &geometry, double distance)
Sets a reference geometry and a maximum distance from this geometry to retrieve features within.
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
Chart series details covering all supported series types.
void setFilterExpression(const QString &filterExpression)
Sets the filter expression used to generate a series against a subset of the source layer.
void setXExpression(const QString &xExpression)
Sets the expression used to generate X-axis values.
void setYExpression(const QString &yExpression)
Sets the expression used to generate Y-axis values.
QgsPlot * plot()
Returns the plot used to render the chart.
void setSortFeatures(bool sorted)
Sets whether features should be sorted when iterating through the vector layer from which the plot da...
int type() const override
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
static QgsLayoutItemChart * create(QgsLayout *layout)
Returns a new chart item for the specified layout.
void setSortAscending(bool ascending)
Sets whether features should be sorted in an ascending order when iterating through the vector layer ...
void setFilterToAtlasFeature(bool filterToAtlas)
Sets series to only use features which intersect the current atlas feature.
void setSeriesList(const QList< QgsLayoutItemChart::SeriesDetails > &seriesList)
Sets the plot series details used to generate the plot data.
void setSourceLayer(QgsVectorLayer *layer)
Sets the source vector layer from which the plot data will be gathered from.
void setFilterOnlyVisibleFeatures(bool visibleOnly)
Sets the series to only use features which are visible in a map item.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
QgsLayoutItemChart(QgsLayout *layout)
Constructor for QgsLayoutItemChart, with the specified parent layout.
QgsLayoutItemMap * map() const
Returns the layout map to use to limit the series' use of features.
void setPlot(QgsPlot *plot)
Sets the plot used to render the chart.
QList< QgsLayoutItemChart::SeriesDetails > seriesList() const
Returns the plot series details used to generate the plot data.
void setSortExpression(const QString &expression)
Sets the expression used to sort features when iterating through the vector layer from which the plot...
QIcon icon() const override
Returns the item's icon.
void setMap(QgsLayoutItemMap *map)
Sets a layout map to use to limit the series' use of features.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
void extentChanged()
Emitted when the map's extent changes.
void mapRotationChanged(double newRotation)
Emitted when the map's rotation changes.
Contains settings and helpers relating to a render of a QgsLayoutItem.
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
QgsLayoutItem(QgsLayout *layout, bool manageZValue=true)
Constructor for QgsLayoutItem, with the specified parent layout.
friend class QgsLayoutItemMap
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
QPointer< QgsLayout > mLayout
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
static Q_DECL_DEPRECATED double scaleFactorFromItemStyle(const QStyleOptionGraphicsItem *style)
Extracts the scale factor from an item style.
Qgis::PlotAxisType type() const
Returns the axis type.
QgsPlotAbstractMetadata * plotMetadata(const QString &type) const
Returns the metadata for the specified plot type.
Contains information about the context of a plot rendering operation.
Base class for plot/chart/graphs.
A container for the context for various read/write operations on objects.
Contains information about the context of a rendering operation.
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
Scoped object for saving and restoring a QPainter object's state.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
void taskCompleted()
Will be emitted by task to indicate its successful completion.
Represents a vector layer which manages a vector based dataset.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
#define QgsDebugError(str)
_LayerRef< QgsVectorLayer > QgsVectorLayerRef