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;
227 if ( !
mLayout || !painter || !painter->device() )
240 QPaintDevice *paintDevice = painter->device();
244 QRectF thisPaintRect = rect();
248 if (
mLayout->renderContext().isPreviewRender() )
250 if ( mNeedsGathering || mIsGathering )
252 if ( mNeedsGathering )
254 mNeedsGathering =
false;
259 painter->setClipRect( thisPaintRect );
261 painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
262 painter->drawRect( thisPaintRect );
263 painter->setBrush( Qt::NoBrush );
265 messageFont.setPointSize( 12 );
266 painter->setFont( messageFont );
267 painter->setPen( QColor( 255, 255, 255, 255 ) );
268 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr(
"Rendering chart" ) );
274 if ( mNeedsGathering )
276 mNeedsGathering =
false;
281 mGatherer->waitForFinished( 60000 );
288 if ( size.width() == 0 || size.height() == 0 )
291 mPlot->setSize( size );
295 painter->scale( 1 / scaleFactor, 1 / scaleFactor );
302 mPlot->render( renderContext, plotRenderContext, mPlotData );
305 if ( mSeriesList.isEmpty() )
308 messageFont.setPointSize( 8 );
309 painter->setFont( messageFont );
310 painter->setPen( QColor( 125, 125, 125, 125 ) );
311 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr(
"Missing chart data" ) );
318 if ( mVectorLayer && !mSeriesList.isEmpty() )
320 mNeedsGathering =
true;
324void QgsLayoutItemChart::refreshData()
326 mGathererTimer.start();
329void QgsLayoutItemChart::gatherData()
341void QgsLayoutItemChart::prepareGatherer()
350 if ( !mVectorLayer || !mPlot || mSeriesList.isEmpty() )
352 mPlotData.clearSeries();
353 mIsGathering =
false;
360 mPlotData.clearSeries();
361 mIsGathering =
false;
374 mPlotData.clearSeries();
375 mIsGathering =
false;
379 if ( QgsVectorLayerXyPlotDataGatherer *xyGatherer =
dynamic_cast<QgsVectorLayerXyPlotDataGatherer *
>( mGatherer.data() ) )
381 QList<QgsVectorLayerXyPlotDataGatherer::XySeriesDetails> xYSeriesList;
384 xYSeriesList << QgsVectorLayerXyPlotDataGatherer::XySeriesDetails( series.name(), series.xExpression(), series.yExpression(), series.filterExpression() );
387 QgsFeatureRequest request;
388 QStringList filterExpressions;
389 for ( QgsLayoutItemChart::SeriesDetails &series : mSeriesList )
391 if ( !series.filterExpression().isEmpty() )
393 filterExpressions << series.filterExpression();
396 if ( !filterExpressions.isEmpty() )
401 if ( mSortFeatures && !mSortExpression.isEmpty() )
403 request.
addOrderBy( mSortExpression, mSortAscending );
406 if ( mFilterToAtlasIntersection )
408 const QgsGeometry atlasGeometry =
mLayout->reportContext().currentGeometry( mVectorLayer->crs() );
409 if ( !atlasGeometry.
isNull() )
414 else if ( mMap && mFilterOnlyVisibleFeatures )
417 if ( mVectorLayer->crs() != mMap->crs() )
419 const QgsCoordinateTransform transform( mVectorLayer->crs(), mMap->crs(),
mLayout->project() );
420 if ( visibleRegionGeometry.
transform( transform ) != Qgis::GeometryOperationResult ::Success )
422 visibleRegionGeometry = QgsGeometry();
425 if ( !visibleRegionGeometry.
isNull() )
432 QgsFeatureIterator featureIterator = mVectorLayer->getFeatures( request );
434 xyGatherer->setFeatureIterator( featureIterator );
436 xyGatherer->setSeriesDetails( xYSeriesList );
442void QgsLayoutItemChart::processData()
444 mPlotData = mGatherer->data();
447 mIsGathering =
false;
455 QDomElement plotElement = document.createElement( u
"plot"_s );
456 mPlot->writeXml( plotElement, document, context );
457 element.appendChild( plotElement );
460 QDomElement seriesListElement = document.createElement( u
"seriesList"_s );
463 QDomElement seriesElement = document.createElement( u
"series"_s );
464 seriesElement.setAttribute( u
"name"_s, series.name() );
465 seriesElement.setAttribute( u
"xExpression"_s, series.xExpression() );
466 seriesElement.setAttribute( u
"yExpression"_s, series.yExpression() );
467 seriesElement.setAttribute( u
"filterExpression"_s, series.filterExpression() );
468 seriesListElement.appendChild( seriesElement );
470 element.appendChild( seriesListElement );
474 element.setAttribute( u
"vectorLayer"_s, mVectorLayer.layerId );
475 element.setAttribute( u
"vectorLayerName"_s, mVectorLayer.name );
476 element.setAttribute( u
"vectorLayerSource"_s, mVectorLayer.source );
477 element.setAttribute( u
"vectorLayerProvider"_s, mVectorLayer.provider );
480 element.setAttribute( u
"sortFeatures"_s, mSortFeatures ? u
"1"_s : u
"0"_s );
481 element.setAttribute( u
"sortAscending"_s, mSortAscending ? u
"1"_s : u
"0"_s );
482 element.setAttribute( u
"sortExpression"_s, mSortExpression );
484 element.setAttribute( u
"sortExpression"_s, mSortExpression );
486 element.setAttribute( u
"filterOnlyVisibleFeatures"_s, mFilterOnlyVisibleFeatures );
487 element.setAttribute( u
"filterToAtlasIntersection"_s, mFilterToAtlasIntersection );
491 element.setAttribute( u
"mapUuid"_s, mMap->uuid() );
499 QDomElement plotElement = element.firstChildElement( u
"plot"_s );
500 if ( !plotElement.isNull() )
505 mPlot->readXml( plotElement, context );
510 const QDomNodeList seriesNodeList = element.firstChildElement( u
"seriesList"_s ).childNodes();
511 for (
int i = 0; i < seriesNodeList.count(); i++ )
513 const QDomElement seriesElement = seriesNodeList.at( i ).toElement();
515 series.
setXExpression( seriesElement.attribute(
"xExpression" ) );
516 series.
setYExpression( seriesElement.attribute(
"yExpression" ) );
518 mSeriesList << series;
521 QString layerId = element.attribute( u
"vectorLayer"_s );
522 QString layerName = element.attribute( u
"vectorLayerName"_s );
523 QString layerSource = element.attribute( u
"vectorLayerSource"_s );
524 QString layerProvider = element.attribute( u
"vectorLayerProvider"_s );
525 mVectorLayer =
QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
526 mVectorLayer.resolveWeakly(
mLayout->project() );
528 mSortFeatures = element.attribute( u
"sortFeatures"_s, u
"0"_s ).toInt();
529 mSortAscending = element.attribute( u
"sortAscending"_s, u
"1"_s ).toInt();
530 mSortExpression = element.attribute( u
"sortExpression"_s );
532 mFilterOnlyVisibleFeatures = element.attribute( u
"filterOnlyVisibleFeatures"_s, u
"1"_s ).toInt();
533 mFilterToAtlasIntersection = element.attribute( u
"filterToAtlasIntersection"_s, u
"0"_s ).toInt();
535 mMapUuid = element.attribute( u
"mapUuid"_s );
543 mNeedsGathering =
true;
550 if ( !mMap && !mMapUuid.isEmpty() &&
mLayout )
552 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