mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[FEATURE] Rendering of data-defined size in legend in "collapsed" mode
Instead of having different marker sizes in legend as separate legend nodes, the new "collapsed" mode packs all sizes into one legend node. This commit only makes it available in the API, not exposed in GUI yet.
This commit is contained in:
parent
a8999639c7
commit
8c4d5bbb95
@ -36,6 +36,7 @@
|
||||
%Include qgscoordinatetransform.sip
|
||||
%Include qgscredentials.sip
|
||||
%Include qgscrscache.sip
|
||||
%Include qgsdatadefinedsizelegend.sip
|
||||
%Include qgsdataitem.sip
|
||||
%Include qgsdataitemprovider.sip
|
||||
%Include qgsdataitemproviderregistry.sip
|
||||
|
@ -151,6 +151,12 @@ Emitted on internal data change so the layer tree model can forward the signal t
|
||||
Construct the node with pointer to its parent layer node
|
||||
%End
|
||||
|
||||
QgsRenderContext *createTemporaryRenderContext() const /Factory/;
|
||||
%Docstring
|
||||
Returns a temporary context or null if legendMapViewData are not valid
|
||||
:rtype: QgsRenderContext
|
||||
%End
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
@ -371,6 +377,30 @@ class QgsWmsLegendNode : QgsLayerTreeModelLegendNode
|
||||
|
||||
};
|
||||
|
||||
|
||||
class QgsDataDefinedSizeLegendNode : QgsLayerTreeModelLegendNode
|
||||
{
|
||||
%Docstring
|
||||
Produces legend node with a marker symbol
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgslayertreemodellegendnode.h"
|
||||
%End
|
||||
public:
|
||||
QgsDataDefinedSizeLegendNode( QgsLayerTreeLayer *nodeLayer, const QgsDataDefinedSizeLegend &settings, QObject *parent /TransferThis/ = 0 );
|
||||
%Docstring
|
||||
Construct the node using QgsDataDefinedSizeLegend as definition of the node's appearance
|
||||
%End
|
||||
|
||||
virtual QVariant data( int role ) const;
|
||||
|
||||
virtual ItemMetrics draw( const QgsLegendSettings &settings, ItemContext *ctx );
|
||||
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
|
@ -760,6 +760,19 @@ Returns list with all diagram settings in the renderer
|
||||
virtual QList< QgsLayerTreeModelLegendNode * > legendItems( QgsLayerTreeLayer *nodeLayer ) const /Factory/;
|
||||
|
||||
|
||||
void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings /Transfer/ );
|
||||
%Docstring
|
||||
Configures appearance of legend. Takes ownership of the passed settings objects.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
|
||||
%Docstring
|
||||
Returns configuration of appearance of legend. Will return null if no configuration has been set.
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsDataDefinedSizeLegend
|
||||
%End
|
||||
|
||||
protected:
|
||||
virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const;
|
||||
|
||||
@ -767,6 +780,8 @@ Returns list with all diagram settings in the renderer
|
||||
virtual QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c ) const;
|
||||
|
||||
|
||||
QgsLinearlyInterpolatedDiagramRenderer( const QgsLinearlyInterpolatedDiagramRenderer &other );
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
|
@ -78,6 +78,7 @@ class QgsCategorizedSymbolRenderer : QgsFeatureRenderer
|
||||
public:
|
||||
|
||||
QgsCategorizedSymbolRenderer( const QString &attrName = QString(), const QgsCategoryList &categories = QgsCategoryList() );
|
||||
~QgsCategorizedSymbolRenderer();
|
||||
|
||||
virtual QgsSymbol *symbolForFeature( QgsFeature &feature, QgsRenderContext &context );
|
||||
virtual QgsSymbol *originalSymbolForFeature( QgsFeature &feature, QgsRenderContext &context );
|
||||
@ -220,10 +221,31 @@ create renderer from XML element
|
||||
:rtype: QgsCategorizedSymbolRenderer
|
||||
%End
|
||||
|
||||
void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings /Transfer/ );
|
||||
%Docstring
|
||||
Configures appearance of legend when renderer is configured to use data-defined size for marker symbols.
|
||||
This allows to configure for what values (symbol sizes) should be shown in the legend, whether to display
|
||||
different symbol sizes collapsed in one legend node or separated across multiple legend nodes etc.
|
||||
|
||||
When renderer does not use data-defined size or does not use marker symbols, these settings will be ignored.
|
||||
Takes ownership of the passed settings objects. Null pointer is a valid input that disables data-defined
|
||||
size legend.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
|
||||
%Docstring
|
||||
Returns configuration of appearance of legend when using data-defined size for marker symbols.
|
||||
Will return null if the functionality is disabled.
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsDataDefinedSizeLegend
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
|
||||
|
||||
void rebuildHash();
|
||||
%Docstring
|
||||
hashtable for faster access to symbols
|
||||
|
@ -7,6 +7,7 @@
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
class QgsRendererRange
|
||||
{
|
||||
|
||||
@ -405,9 +406,30 @@ create renderer from XML element
|
||||
:rtype: QgsGraduatedSymbolRenderer
|
||||
%End
|
||||
|
||||
void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings /Transfer/ );
|
||||
%Docstring
|
||||
Configures appearance of legend when renderer is configured to use data-defined size for marker symbols.
|
||||
This allows to configure for what values (symbol sizes) should be shown in the legend, whether to display
|
||||
different symbol sizes collapsed in one legend node or separated across multiple legend nodes etc.
|
||||
|
||||
When renderer does not use data-defined size or does not use marker symbols, these settings will be ignored.
|
||||
Takes ownership of the passed settings objects. Null pointer is a valid input that disables data-defined
|
||||
size legend.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
|
||||
%Docstring
|
||||
Returns configuration of appearance of legend when using data-defined size for marker symbols.
|
||||
Will return null if the functionality is disabled.
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsDataDefinedSizeLegend
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
|
||||
QgsSymbol *symbolForValue( double value );
|
||||
%Docstring
|
||||
attribute index (derived from attribute name in startRender)
|
||||
|
@ -94,6 +94,22 @@ Identation level that tells how deep the item is in a hierarchy of items. For fl
|
||||
Set symbol of the item. Takes ownership of symbol.
|
||||
%End
|
||||
|
||||
void setDataDefinedSizeLegendSettings( QgsDataDefinedSizeLegend *settings /Transfer/ );
|
||||
%Docstring
|
||||
Sets extra information about data-defined size. If set, this item should be converted to QgsDataDefinedSizeLegendNode
|
||||
rather than QgsSymbolLegendNode instance as usual. Passing null removes any data-defined size legend settings.
|
||||
|
||||
Takes ownership of the settings object.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
QgsDataDefinedSizeLegend *dataDefinedSizeLegendSettings() const;
|
||||
%Docstring
|
||||
Returns extra information for data-defined size legend rendering. Normally it returns null.
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsDataDefinedSizeLegend
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
class QgsSingleSymbolRenderer : QgsFeatureRenderer
|
||||
{
|
||||
|
||||
@ -16,6 +17,7 @@ class QgsSingleSymbolRenderer : QgsFeatureRenderer
|
||||
public:
|
||||
|
||||
QgsSingleSymbolRenderer( QgsSymbol *symbol /Transfer/ );
|
||||
~QgsSingleSymbolRenderer();
|
||||
|
||||
virtual QgsSymbol *symbolForFeature( QgsFeature &feature, QgsRenderContext &context );
|
||||
virtual QgsSymbol *originalSymbolForFeature( QgsFeature &feature, QgsRenderContext &context );
|
||||
@ -58,6 +60,26 @@ create renderer from XML element
|
||||
:rtype: QgsSingleSymbolRenderer
|
||||
%End
|
||||
|
||||
void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings /Transfer/ );
|
||||
%Docstring
|
||||
Configures appearance of legend when renderer is configured to use data-defined size for marker symbols.
|
||||
This allows to configure for what values (symbol sizes) should be shown in the legend, whether to display
|
||||
different symbol sizes collapsed in one legend node or separated across multiple legend nodes etc.
|
||||
|
||||
When renderer does not use data-defined size or does not use marker symbols, these settings will be ignored.
|
||||
Takes ownership of the passed settings objects. Null pointer is a valid input that disables data-defined
|
||||
size legend.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
|
||||
%Docstring
|
||||
Returns configuration of appearance of legend when using data-defined size for marker symbols.
|
||||
Will return null if the functionality is disabled.
|
||||
.. versionadded:: 3.0
|
||||
:rtype: QgsDataDefinedSizeLegend
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
@ -141,6 +141,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgscredentials.cpp
|
||||
qgscrscache.cpp
|
||||
qgsdartmeasurement.cpp
|
||||
qgsdatadefinedsizelegend.cpp
|
||||
qgsdataitem.cpp
|
||||
qgsdataitemprovider.cpp
|
||||
qgsdataitemproviderregistry.cpp
|
||||
@ -738,6 +739,7 @@ SET(QGIS_CORE_HDRS
|
||||
qgscrscache.h
|
||||
qgscsexception.h
|
||||
qgsdartmeasurement.h
|
||||
qgsdatadefinedsizelegend.h
|
||||
qgsdataitem.h
|
||||
qgsdataitemprovider.h
|
||||
qgsdataitemproviderregistry.h
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "qgslayertreemodellegendnode.h"
|
||||
|
||||
#include "qgsdatadefinedsizelegend.h"
|
||||
#include "qgslayertree.h"
|
||||
#include "qgslayertreemodel.h"
|
||||
#include "qgslegendsettings.h"
|
||||
@ -215,22 +216,23 @@ void QgsSymbolLegendNode::uncheckAllItems()
|
||||
checkAll( false );
|
||||
}
|
||||
|
||||
inline
|
||||
QgsRenderContext *QgsSymbolLegendNode::createTemporaryRenderContext() const
|
||||
QgsRenderContext *QgsLayerTreeModelLegendNode::createTemporaryRenderContext() const
|
||||
{
|
||||
double scale = 0.0;
|
||||
double mupp = 0.0;
|
||||
int dpi = 0;
|
||||
if ( model() )
|
||||
model()->legendMapViewData( &mupp, &dpi, &scale );
|
||||
bool validData = !qgsDoubleNear( mupp, 0.0 ) && dpi != 0 && !qgsDoubleNear( scale, 0.0 );
|
||||
|
||||
if ( qgsDoubleNear( mupp, 0.0 ) || dpi == 0 || qgsDoubleNear( scale, 0.0 ) )
|
||||
return nullptr;
|
||||
|
||||
// setup temporary render context
|
||||
std::unique_ptr<QgsRenderContext> context( new QgsRenderContext );
|
||||
QgsRenderContext *context = new QgsRenderContext;
|
||||
context->setScaleFactor( dpi / 25.4 );
|
||||
context->setRendererScale( scale );
|
||||
context->setMapToPixel( QgsMapToPixel( mupp ) );
|
||||
return validData ? context.release() : nullptr;
|
||||
return context;
|
||||
}
|
||||
|
||||
void QgsSymbolLegendNode::checkAll( bool state )
|
||||
@ -718,3 +720,71 @@ void QgsWmsLegendNode::invalidateMapBasedData()
|
||||
mValid = false;
|
||||
emit dataChanged();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
QgsDataDefinedSizeLegendNode::QgsDataDefinedSizeLegendNode( QgsLayerTreeLayer *nodeLayer, const QgsDataDefinedSizeLegend &settings, QObject *parent )
|
||||
: QgsLayerTreeModelLegendNode( nodeLayer, parent )
|
||||
, mSettings( new QgsDataDefinedSizeLegend( settings ) )
|
||||
{
|
||||
}
|
||||
|
||||
QVariant QgsDataDefinedSizeLegendNode::data( int role ) const
|
||||
{
|
||||
if ( role == Qt::DecorationRole )
|
||||
{
|
||||
cacheImage();
|
||||
return QPixmap::fromImage( mImage );
|
||||
}
|
||||
else if ( role == Qt::SizeHintRole )
|
||||
{
|
||||
cacheImage();
|
||||
return mImage.size();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QgsLayerTreeModelLegendNode::ItemMetrics QgsDataDefinedSizeLegendNode::draw( const QgsLegendSettings &settings, QgsLayerTreeModelLegendNode::ItemContext *ctx )
|
||||
{
|
||||
// setup temporary render context
|
||||
QgsRenderContext context;
|
||||
context.setScaleFactor( settings.dpi() / 25.4 );
|
||||
context.setRendererScale( settings.mapScale() );
|
||||
context.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * context.scaleFactor() ) ) );
|
||||
context.setForceVectorOutput( true );
|
||||
|
||||
if ( ctx )
|
||||
{
|
||||
context.setPainter( ctx->painter );
|
||||
ctx->painter->save();
|
||||
ctx->painter->setRenderHint( QPainter::Antialiasing );
|
||||
ctx->painter->translate( ctx->point );
|
||||
ctx->painter->scale( 1 / context.scaleFactor(), 1 / context.scaleFactor() );
|
||||
}
|
||||
|
||||
QgsDataDefinedSizeLegend ddsLegend( *mSettings );
|
||||
ddsLegend.setFont( settings.style( QgsLegendStyle::SymbolLabel ).font() );
|
||||
ddsLegend.setTextColor( settings.fontColor() );
|
||||
|
||||
QSize contentSize;
|
||||
int labelXOffset;
|
||||
ddsLegend.drawCollapsedLegend( context, &contentSize, &labelXOffset );
|
||||
|
||||
if ( ctx )
|
||||
ctx->painter->restore();
|
||||
|
||||
ItemMetrics im;
|
||||
im.symbolSize = QSizeF( ( contentSize.width() - labelXOffset ) / context.scaleFactor(), contentSize.height() / context.scaleFactor() );
|
||||
im.labelSize = QSizeF( labelXOffset / context.scaleFactor(), contentSize.height() / context.scaleFactor() );
|
||||
return im;
|
||||
}
|
||||
|
||||
|
||||
void QgsDataDefinedSizeLegendNode::cacheImage() const
|
||||
{
|
||||
if ( mImage.isNull() )
|
||||
{
|
||||
std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() );
|
||||
mImage = mSettings->collapsedLegendImage( *context.get() );
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +131,9 @@ class CORE_EXPORT QgsLayerTreeModelLegendNode : public QObject
|
||||
//! Construct the node with pointer to its parent layer node
|
||||
explicit QgsLayerTreeModelLegendNode( QgsLayerTreeLayer *nodeL, QObject *parent SIP_TRANSFERTHIS = nullptr );
|
||||
|
||||
//! Returns a temporary context or null if legendMapViewData are not valid
|
||||
QgsRenderContext *createTemporaryRenderContext() const SIP_FACTORY;
|
||||
|
||||
protected:
|
||||
QgsLayerTreeLayer *mLayerNode = nullptr;
|
||||
bool mEmbeddedInParent;
|
||||
@ -237,9 +240,6 @@ class CORE_EXPORT QgsSymbolLegendNode : public QgsLayerTreeModelLegendNode
|
||||
// ident the symbol icon to make it look like a tree structure
|
||||
static const int INDENT_SIZE = 20;
|
||||
|
||||
// return a temporary context or null if legendMapViewData are not valid
|
||||
QgsRenderContext *createTemporaryRenderContext() const;
|
||||
|
||||
/** Sets all items belonging to the same layer as this node to the same check state.
|
||||
* \param state check state
|
||||
*/
|
||||
@ -380,4 +380,27 @@ class CORE_EXPORT QgsWmsLegendNode : public QgsLayerTreeModelLegendNode
|
||||
mutable std::unique_ptr<QgsImageFetcher> mFetcher;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* Produces legend node with a marker symbol
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class CORE_EXPORT QgsDataDefinedSizeLegendNode : public QgsLayerTreeModelLegendNode
|
||||
{
|
||||
public:
|
||||
//! Construct the node using QgsDataDefinedSizeLegend as definition of the node's appearance
|
||||
QgsDataDefinedSizeLegendNode( QgsLayerTreeLayer *nodeLayer, const QgsDataDefinedSizeLegend &settings, QObject *parent SIP_TRANSFERTHIS = nullptr );
|
||||
|
||||
virtual QVariant data( int role ) const override;
|
||||
|
||||
ItemMetrics draw( const QgsLegendSettings &settings, ItemContext *ctx ) override;
|
||||
|
||||
private:
|
||||
void cacheImage() const;
|
||||
|
||||
std::unique_ptr<QgsDataDefinedSizeLegend> mSettings;
|
||||
mutable QImage mImage;
|
||||
};
|
||||
|
||||
#endif // QGSLAYERTREEMODELLEGENDNODE_H
|
||||
|
289
src/core/qgsdatadefinedsizelegend.cpp
Normal file
289
src/core/qgsdatadefinedsizelegend.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
/***************************************************************************
|
||||
qgsdatadefinedsizelegend.cpp
|
||||
--------------------------------------
|
||||
Date : June 2017
|
||||
Copyright : (C) 2017 by Martin Dobias
|
||||
Email : wonder dot sk at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsdatadefinedsizelegend.h"
|
||||
|
||||
#include "qgsproperty.h"
|
||||
#include "qgspropertytransformer.h"
|
||||
#include "qgssymbollayerutils.h"
|
||||
|
||||
QgsDataDefinedSizeLegend::QgsDataDefinedSizeLegend()
|
||||
{
|
||||
}
|
||||
|
||||
QgsDataDefinedSizeLegend::QgsDataDefinedSizeLegend( const QgsDataDefinedSizeLegend &other )
|
||||
: mType( other.mType )
|
||||
, mTitleLabel( other.mTitleLabel )
|
||||
, mSizeClasses( other.mSizeClasses )
|
||||
, mSymbol( other.mSymbol.get() ? other.mSymbol->clone() : nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
QgsDataDefinedSizeLegend &QgsDataDefinedSizeLegend::operator=( const QgsDataDefinedSizeLegend &other )
|
||||
{
|
||||
if ( this != &other )
|
||||
{
|
||||
mType = other.mType;
|
||||
mTitleLabel = other.mTitleLabel;
|
||||
mSizeClasses = other.mSizeClasses;
|
||||
mSymbol.reset( other.mSymbol.get() ? other.mSymbol->clone() : nullptr );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void QgsDataDefinedSizeLegend::updateFromSymbolAndProperty( const QgsMarkerSymbol *symbol, const QgsProperty &ddSize )
|
||||
{
|
||||
mSymbol.reset( symbol->clone() );
|
||||
mSymbol->setDataDefinedSize( QgsProperty() ); // original symbol may have had data-defined size associated
|
||||
|
||||
mTitleLabel = ddSize.propertyType() == QgsProperty::ExpressionBasedProperty ? ddSize.expressionString() : ddSize.field();
|
||||
|
||||
// automatically generated classes
|
||||
if ( const QgsSizeScaleTransformer *sizeTransformer = dynamic_cast< const QgsSizeScaleTransformer * >( ddSize.transformer() ) )
|
||||
{
|
||||
mSizeClasses.clear();
|
||||
Q_FOREACH ( double v, QgsSymbolLayerUtils::prettyBreaks( sizeTransformer->minValue(), sizeTransformer->maxValue(), 4 ) )
|
||||
{
|
||||
mSizeClasses << SizeClass( sizeTransformer->size( v ), QString::number( v ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QgsLegendSymbolList QgsDataDefinedSizeLegend::legendSymbolList() const
|
||||
{
|
||||
QgsLegendSymbolList lst;
|
||||
if ( !mTitleLabel.isEmpty() )
|
||||
{
|
||||
QgsLegendSymbolItem title( nullptr, mTitleLabel, QString() );
|
||||
lst << title;
|
||||
}
|
||||
|
||||
if ( mType == LegendCollapsed )
|
||||
{
|
||||
QgsLegendSymbolItem i;
|
||||
i.setDataDefinedSizeLegendSettings( new QgsDataDefinedSizeLegend( *this ) );
|
||||
lst << i;
|
||||
return lst;
|
||||
}
|
||||
else if ( mType == LegendSeparated )
|
||||
{
|
||||
Q_FOREACH ( const SizeClass &cl, mSizeClasses )
|
||||
{
|
||||
QgsLegendSymbolItem si( mSymbol.get(), cl.label, QString() );
|
||||
QgsMarkerSymbol *s = static_cast<QgsMarkerSymbol *>( si.symbol() );
|
||||
s->setSize( cl.size );
|
||||
lst << si;
|
||||
}
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
|
||||
|
||||
void QgsDataDefinedSizeLegend::drawCollapsedLegend( QgsRenderContext &context, QSize *outputSize, int *labelXOffset ) const
|
||||
{
|
||||
if ( mType != LegendCollapsed || mSizeClasses.isEmpty() || !mSymbol )
|
||||
{
|
||||
if ( outputSize )
|
||||
*outputSize = QSize();
|
||||
if ( labelXOffset )
|
||||
*labelXOffset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// parameters that could be configurable
|
||||
double hLengthLineMM = 2; // extra horizontal space to be occupied by callout line
|
||||
double hSpaceLineTextMM = 1; // horizontal space between end of the line and start of the text
|
||||
|
||||
std::unique_ptr<QgsMarkerSymbol> s( mSymbol->clone() );
|
||||
|
||||
// make sure we draw bigger symbols first
|
||||
QList<SizeClass> classes = mSizeClasses;
|
||||
std::sort( classes.begin(), classes.end(), []( const SizeClass & a, const SizeClass & b ) { return a.size > b.size; } );
|
||||
|
||||
int hLengthLine = qRound( context.convertToPainterUnits( hLengthLineMM, QgsUnitTypes::RenderMillimeters ) );
|
||||
int hSpaceLineText = qRound( context.convertToPainterUnits( hSpaceLineTextMM, QgsUnitTypes::RenderMillimeters ) );
|
||||
int dpm = qRound( context.scaleFactor() * 1000 ); // scale factor = dots per millimeter
|
||||
|
||||
// get font metrics - we need a temporary image just to get the metrics right for the given DPI
|
||||
QImage tmpImg( QSize( 1, 1 ), QImage::Format_ARGB32_Premultiplied );
|
||||
tmpImg.setDotsPerMeterX( dpm );
|
||||
tmpImg.setDotsPerMeterY( dpm );
|
||||
QFontMetrics fm( mFont, &tmpImg );
|
||||
int textHeight = fm.height();
|
||||
int leading = fm.leading();
|
||||
int minTextDistY = textHeight + leading;
|
||||
|
||||
//
|
||||
// determine layout of the rendered elements
|
||||
//
|
||||
|
||||
// find out how wide the text will be
|
||||
int maxTextWidth = 0;
|
||||
Q_FOREACH ( const SizeClass &c, classes )
|
||||
{
|
||||
int w = fm.width( c.label );
|
||||
if ( w > maxTextWidth )
|
||||
maxTextWidth = w;
|
||||
}
|
||||
|
||||
// find out size of the largest symbol
|
||||
double largestSize = classes.at( 0 ).size;
|
||||
double outputLargestSize = context.convertToPainterUnits( largestSize, s->sizeUnit(), s->sizeMapUnitScale() );
|
||||
|
||||
// find out top Y coordinate for individual symbol sizes
|
||||
QList<int> symbolTopY;
|
||||
Q_FOREACH ( const SizeClass &c, classes )
|
||||
{
|
||||
double outputSymbolSize = context.convertToPainterUnits( c.size, s->sizeUnit(), s->sizeMapUnitScale() );
|
||||
switch ( mVAlign )
|
||||
{
|
||||
case AlignCenter:
|
||||
symbolTopY << qRound( outputLargestSize / 2 - outputSymbolSize / 2 );
|
||||
break;
|
||||
case AlignBottom:
|
||||
symbolTopY << qRound( outputLargestSize - outputSymbolSize );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// determine Y coordinate of texts: ideally they should be at the same level as symbolTopY
|
||||
// but we need to avoid overlapping texts, so adjust the vertical positions
|
||||
int middleIndex = 0; // classes.count() / 2; // will get the ideal position
|
||||
QList<int> textCenterY;
|
||||
int lastY = symbolTopY[middleIndex];
|
||||
textCenterY << lastY;
|
||||
for ( int i = middleIndex + 1; i < classes.count(); ++i )
|
||||
{
|
||||
int symbolY = symbolTopY[i];
|
||||
if ( symbolY - lastY < minTextDistY )
|
||||
symbolY = lastY + minTextDistY;
|
||||
textCenterY << symbolY;
|
||||
lastY = symbolY;
|
||||
}
|
||||
|
||||
int textTopY = textCenterY.first() - textHeight / 2;
|
||||
int textBottomY = textCenterY.last() + textHeight / 2;
|
||||
int totalTextHeight = textBottomY - textTopY;
|
||||
|
||||
int fullWidth = outputLargestSize + hLengthLine + hSpaceLineText + maxTextWidth;
|
||||
int fullHeight = qMax( qRound( outputLargestSize ) - textTopY, totalTextHeight );
|
||||
|
||||
if ( outputSize )
|
||||
*outputSize = QSize( fullWidth, fullHeight );
|
||||
if ( labelXOffset )
|
||||
*labelXOffset = outputLargestSize + hLengthLine + hSpaceLineText;
|
||||
|
||||
if ( !context.painter() )
|
||||
return; // only layout
|
||||
|
||||
//
|
||||
// drawing
|
||||
//
|
||||
|
||||
QPainter *p = context.painter();
|
||||
|
||||
p->save();
|
||||
p->translate( 0, -textTopY );
|
||||
|
||||
// draw symbols first so that they do not cover
|
||||
Q_FOREACH ( const SizeClass &c, classes )
|
||||
{
|
||||
s->setSize( c.size );
|
||||
|
||||
double outputSymbolSize = context.convertToPainterUnits( c.size, s->sizeUnit(), s->sizeMapUnitScale() );
|
||||
double tx = ( outputLargestSize - outputSymbolSize ) / 2;
|
||||
|
||||
p->save();
|
||||
switch ( mVAlign )
|
||||
{
|
||||
case AlignCenter:
|
||||
p->translate( tx, ( outputLargestSize - outputSymbolSize ) / 2 );
|
||||
break;
|
||||
case AlignBottom:
|
||||
p->translate( tx, outputLargestSize - outputSymbolSize );
|
||||
break;
|
||||
}
|
||||
s->drawPreviewIcon( p, QSize( outputSymbolSize, outputSymbolSize ) );
|
||||
p->restore();
|
||||
}
|
||||
|
||||
p->setPen( mTextColor );
|
||||
p->setFont( mFont );
|
||||
|
||||
int i = 0;
|
||||
Q_FOREACH ( const SizeClass &c, classes )
|
||||
{
|
||||
// line from symbol to the text
|
||||
p->drawLine( outputLargestSize / 2, symbolTopY[i], outputLargestSize + hLengthLine, textCenterY[i] );
|
||||
|
||||
// draw label
|
||||
QRect rect( outputLargestSize + hLengthLine + hSpaceLineText, textCenterY[i] - textHeight / 2,
|
||||
maxTextWidth, textHeight );
|
||||
p->drawText( rect, mTextAlignment, c.label );
|
||||
i++;
|
||||
}
|
||||
|
||||
p->restore();
|
||||
}
|
||||
|
||||
|
||||
QImage QgsDataDefinedSizeLegend::collapsedLegendImage( QgsRenderContext &context, double paddingMM ) const
|
||||
{
|
||||
if ( mType != LegendCollapsed || mSizeClasses.isEmpty() || !mSymbol )
|
||||
return QImage();
|
||||
|
||||
// find out the size first
|
||||
QSize contentSize;
|
||||
drawCollapsedLegend( context, &contentSize );
|
||||
|
||||
int padding = qRound( context.convertToPainterUnits( paddingMM, QgsUnitTypes::RenderMillimeters ) );
|
||||
int dpm = qRound( context.scaleFactor() * 1000 ); // scale factor = dots per millimeter
|
||||
|
||||
QImage img( contentSize.width() + padding * 2, contentSize.height() + padding * 2, QImage::Format_ARGB32_Premultiplied );
|
||||
img.setDotsPerMeterX( dpm );
|
||||
img.setDotsPerMeterY( dpm );
|
||||
img.fill( Qt::transparent );
|
||||
|
||||
QPainter painter( &img );
|
||||
painter.setRenderHint( QPainter::Antialiasing, true );
|
||||
|
||||
painter.translate( padding, padding ); // so we do not need to care about padding at all
|
||||
|
||||
// now do the rendering
|
||||
QPainter *oldPainter = context.painter();
|
||||
context.setPainter( &painter );
|
||||
drawCollapsedLegend( context );
|
||||
context.setPainter( oldPainter );
|
||||
|
||||
painter.end();
|
||||
return img;
|
||||
}
|
||||
|
||||
QgsDataDefinedSizeLegend *QgsDataDefinedSizeLegend::readTypeAndAlignmentFromXml( const QDomElement &elem )
|
||||
{
|
||||
if ( elem.isNull() )
|
||||
return nullptr;
|
||||
QgsDataDefinedSizeLegend *ddsLegend = new QgsDataDefinedSizeLegend;
|
||||
ddsLegend->setLegendType( elem.attribute( "type" ) == "collapsed" ? LegendCollapsed : LegendSeparated );
|
||||
ddsLegend->setVerticalAlignment( elem.attribute( "valign" ) == "center" ? AlignCenter : AlignBottom );
|
||||
return ddsLegend;
|
||||
}
|
||||
|
||||
void QgsDataDefinedSizeLegend::writeTypeAndAlignmentToXml( const QgsDataDefinedSizeLegend &ddsLegend, QDomElement &elem )
|
||||
{
|
||||
elem.setAttribute( "type", ddsLegend.legendType() == LegendCollapsed ? "collapsed" : "separated" );
|
||||
elem.setAttribute( "valign", ddsLegend.verticalAlignment() == AlignCenter ? "center" : "bottom" );
|
||||
}
|
145
src/core/qgsdatadefinedsizelegend.h
Normal file
145
src/core/qgsdatadefinedsizelegend.h
Normal file
@ -0,0 +1,145 @@
|
||||
/***************************************************************************
|
||||
qgsdatadefinedsizelegend.cpp
|
||||
--------------------------------------
|
||||
Date : June 2017
|
||||
Copyright : (C) 2017 by Martin Dobias
|
||||
Email : wonder dot sk at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSDATADEFINEDSIZELEGEND_H
|
||||
#define QGSDATADEFINEDSIZELEGEND_H
|
||||
|
||||
#include "qgslegendsymbolitem.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
|
||||
class QDomElement;
|
||||
class QgsMarkerSymbol;
|
||||
class QgsProperty;
|
||||
class QgsRenderContext;
|
||||
|
||||
|
||||
/** \ingroup core
|
||||
* Object that keeps configuration of appearance of marker symbol's data-defined size in legend.
|
||||
* For example: the list of classes (size values), whether the classes should appear in separate
|
||||
* legend nodes or whether to collapse them into one legend node.
|
||||
*
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class CORE_EXPORT QgsDataDefinedSizeLegend
|
||||
{
|
||||
public:
|
||||
QgsDataDefinedSizeLegend();
|
||||
|
||||
QgsDataDefinedSizeLegend( const QgsDataDefinedSizeLegend &other );
|
||||
QgsDataDefinedSizeLegend &operator=( const QgsDataDefinedSizeLegend &other );
|
||||
|
||||
//! Determines how to display data-defined size legend
|
||||
enum LegendType
|
||||
{
|
||||
LegendSeparated, //!< Each class (size value) has a separate legend node
|
||||
LegendCollapsed, //!< All classes are rendered within one legend node
|
||||
};
|
||||
|
||||
//! How to vertically align symbols when all classes go into one node
|
||||
enum VerticalAlignment
|
||||
{
|
||||
AlignCenter, //!< Symbols are aligned to the center
|
||||
AlignBottom, //!< Symbols are aligned to the bottom
|
||||
};
|
||||
|
||||
//! Definition of one class for the legend
|
||||
struct SizeClass
|
||||
{
|
||||
SizeClass( double size, const QString &label ): size( size ), label( label ) {}
|
||||
|
||||
double size; //!< Marker size in units used by the symbol (usually millimeters)
|
||||
QString label; //!< Label to be shown with the particular symbol size
|
||||
};
|
||||
|
||||
//! Sets how the legend should be rendered
|
||||
void setLegendType( LegendType type ) { mType = type; }
|
||||
//! Returns how the legend should be rendered
|
||||
LegendType legendType() const { return mType; }
|
||||
|
||||
//! Sets marker symbol that will be used to draw markers in legend
|
||||
void setSymbol( QgsMarkerSymbol *symbol SIP_TRANSFER ) { mSymbol.reset( symbol ); }
|
||||
//! Returns marker symbol that will be used to draw markers in legend
|
||||
QgsMarkerSymbol *symbol() const { return mSymbol.get(); }
|
||||
|
||||
//! Sets list of classes: each class is a pair of symbol size (in units used by the symbol) and label
|
||||
void setClasses( const QList<QgsDataDefinedSizeLegend::SizeClass> &classes ) { mSizeClasses = classes; }
|
||||
//! Returns list of classes: each class is a pair of symbol size (in units used by the symbol) and label
|
||||
QList<QgsDataDefinedSizeLegend::SizeClass> classes() const { return mSizeClasses; }
|
||||
|
||||
//! Sets title label for data-defined size legend
|
||||
void setTitle( const QString &title ) { mTitleLabel = title; }
|
||||
//! Returns title label for data-defined size legend
|
||||
QString title() const { return mTitleLabel; }
|
||||
|
||||
//! Sets vertical alignment of symbols - only valid for collapsed legend
|
||||
void setVerticalAlignment( VerticalAlignment vAlign ) { mVAlign = vAlign; }
|
||||
//! Returns vertical alignment of symbols - only valid for collapsed legend
|
||||
VerticalAlignment verticalAlignment() const { return mVAlign; }
|
||||
|
||||
//! Sets font used for rendering of labels - only valid for collapsed legend
|
||||
void setFont( const QFont &font ) { mFont = font; }
|
||||
//! Returns font used for rendering of labels - only valid for collapsed legend
|
||||
QFont font() const { return mFont; }
|
||||
|
||||
//! Sets text color for rendering of labels - only valid for collapsed legend
|
||||
void setTextColor( const QColor &color ) { mTextColor = color; }
|
||||
//! Returns text color for rendering of labels - only valid for collapsed legend
|
||||
QColor textColor() const { return mTextColor; }
|
||||
|
||||
//! Sets horizontal text alignment for rendering of labels - only valid for collapsed legend
|
||||
void setTextAlignment( Qt::AlignmentFlag flag ) { mTextAlignment = flag; }
|
||||
//! Returns horizontal text alignment for rendering of labels - only valid for collapsed legend
|
||||
Qt::AlignmentFlag textAlignment() const { return mTextAlignment; }
|
||||
|
||||
//
|
||||
|
||||
//! Updates the list of classes, source symbol and title label from given symbol and property
|
||||
void updateFromSymbolAndProperty( const QgsMarkerSymbol *symbol, const QgsProperty &ddSize );
|
||||
|
||||
//! Generates legend symbol items according to the configuration
|
||||
QgsLegendSymbolList legendSymbolList() const;
|
||||
|
||||
//! Draw the legend if using LegendOneNodeForAll and optionally output size of the legend and x offset of labels (in painter units).
|
||||
//! If the painter in context is null, it only does size calculation without actual rendering.
|
||||
//! Does nothing if legend is not configured as collapsed.
|
||||
void drawCollapsedLegend( QgsRenderContext &context, QSize *outputSize SIP_OUT = nullptr, int *labelXOffset SIP_OUT = nullptr ) const;
|
||||
|
||||
//! Returns output image that would be shown in the legend. Returns invalid image if legend is not configured as collapsed.
|
||||
QImage collapsedLegendImage( QgsRenderContext &context, double paddingMM = 1 ) const;
|
||||
|
||||
//! Creates instance from given element and returns it (caller takes ownership). Returns null on error.
|
||||
//! \note only reads legend type and vertical alignment of symbols
|
||||
//! \note This is a temporary method and may be removed in the future
|
||||
static QgsDataDefinedSizeLegend *readTypeAndAlignmentFromXml( const QDomElement &elem ) SIP_FACTORY;
|
||||
|
||||
//! Writes configuration to the given XML element.
|
||||
//! \note only writes legend type and vertical alignment of symbols
|
||||
//! \note This is a temporary method and may be removed in the future
|
||||
static void writeTypeAndAlignmentToXml( const QgsDataDefinedSizeLegend &ddsLegend, QDomElement &elem );
|
||||
|
||||
private:
|
||||
LegendType mType = LegendSeparated;
|
||||
QString mTitleLabel; //!< Title label for the following size-based item(s)
|
||||
QList<SizeClass> mSizeClasses; //!< List of classes: symbol size (in whatever units symbol uses) + label
|
||||
std::unique_ptr<QgsMarkerSymbol> mSymbol;
|
||||
VerticalAlignment mVAlign = AlignBottom;
|
||||
QFont mFont;
|
||||
QColor mTextColor = Qt::black;
|
||||
Qt::AlignmentFlag mTextAlignment = Qt::AlignLeft;
|
||||
};
|
||||
|
||||
#endif // QGSDATADEFINEDSIZELEGEND_H
|
@ -13,6 +13,8 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
#include "qgsdiagramrenderer.h"
|
||||
|
||||
#include "qgsdatadefinedsizelegend.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "diagram/qgstextdiagram.h"
|
||||
#include "diagram/qgspiediagram.h"
|
||||
@ -610,11 +612,20 @@ void QgsSingleCategoryDiagramRenderer::writeXml( QDomElement &layerElem, QDomDoc
|
||||
}
|
||||
|
||||
|
||||
QgsLinearlyInterpolatedDiagramRenderer::QgsLinearlyInterpolatedDiagramRenderer(): QgsDiagramRenderer()
|
||||
QgsLinearlyInterpolatedDiagramRenderer::QgsLinearlyInterpolatedDiagramRenderer()
|
||||
: QgsDiagramRenderer()
|
||||
{
|
||||
mInterpolationSettings.classificationAttributeIsExpression = false;
|
||||
}
|
||||
|
||||
QgsLinearlyInterpolatedDiagramRenderer::QgsLinearlyInterpolatedDiagramRenderer( const QgsLinearlyInterpolatedDiagramRenderer &other )
|
||||
: QgsDiagramRenderer( other )
|
||||
, mSettings( other.mSettings )
|
||||
, mInterpolationSettings( other.mInterpolationSettings )
|
||||
, mDataDefinedSizeLegend( other.mDataDefinedSizeLegend ? new QgsDataDefinedSizeLegend( *other.mDataDefinedSizeLegend ) : nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
QgsLinearlyInterpolatedDiagramRenderer *QgsLinearlyInterpolatedDiagramRenderer::clone() const
|
||||
{
|
||||
return new QgsLinearlyInterpolatedDiagramRenderer( *this );
|
||||
@ -684,6 +695,13 @@ void QgsLinearlyInterpolatedDiagramRenderer::readXml( const QDomElement &elem, c
|
||||
{
|
||||
mSettings.readXml( settingsElem );
|
||||
}
|
||||
|
||||
QDomElement ddsLegendSizeElem = elem.firstChildElement( "data-defined-size-legend" );
|
||||
if ( !ddsLegendSizeElem.isNull() )
|
||||
{
|
||||
mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readTypeAndAlignmentFromXml( ddsLegendSizeElem ) );
|
||||
}
|
||||
|
||||
_readXml( elem, context );
|
||||
}
|
||||
|
||||
@ -705,6 +723,14 @@ void QgsLinearlyInterpolatedDiagramRenderer::writeXml( QDomElement &layerElem, Q
|
||||
rendererElem.setAttribute( QStringLiteral( "classificationField" ), mInterpolationSettings.classificationField );
|
||||
}
|
||||
mSettings.writeXml( rendererElem, doc );
|
||||
|
||||
if ( mDataDefinedSizeLegend )
|
||||
{
|
||||
QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
|
||||
QgsDataDefinedSizeLegend::writeTypeAndAlignmentToXml( *mDataDefinedSizeLegend, ddsLegendElem );
|
||||
rendererElem.appendChild( ddsLegendElem );
|
||||
}
|
||||
|
||||
_writeXml( rendererElem, doc, context );
|
||||
layerElem.appendChild( rendererElem );
|
||||
}
|
||||
@ -745,17 +771,42 @@ QList< QgsLayerTreeModelLegendNode * > QgsLinearlyInterpolatedDiagramRenderer::l
|
||||
if ( mShowSizeLegend && mDiagram && mSizeLegendSymbol )
|
||||
{
|
||||
// add size legend
|
||||
|
||||
QgsMarkerSymbol *legendSymbol = mSizeLegendSymbol.get()->clone();
|
||||
legendSymbol->setSizeUnit( mSettings.sizeType );
|
||||
legendSymbol->setSizeMapUnitScale( mSettings.sizeScale );
|
||||
|
||||
QList<QgsDataDefinedSizeLegend::SizeClass> sizeClasses;
|
||||
Q_FOREACH ( double v, QgsSymbolLayerUtils::prettyBreaks( mInterpolationSettings.lowerValue, mInterpolationSettings.upperValue, 4 ) )
|
||||
{
|
||||
double size = mDiagram->legendSize( v, mSettings, mInterpolationSettings );
|
||||
QgsLegendSymbolItem si( mSizeLegendSymbol.get(), QString::number( v ), QString() );
|
||||
QgsMarkerSymbol *s = static_cast<QgsMarkerSymbol *>( si.symbol() );
|
||||
s->setSize( size );
|
||||
s->setSizeUnit( mSettings.sizeType );
|
||||
s->setSizeMapUnitScale( mSettings.sizeScale );
|
||||
nodes << new QgsSymbolLegendNode( nodeLayer, si );
|
||||
sizeClasses << QgsDataDefinedSizeLegend::SizeClass( size, QString::number( v ) );
|
||||
}
|
||||
|
||||
QgsDataDefinedSizeLegend ddSizeLegend;
|
||||
if ( mDataDefinedSizeLegend ) // copy legend configuration if any...
|
||||
ddSizeLegend = *mDataDefinedSizeLegend;
|
||||
ddSizeLegend.setSymbol( legendSymbol ); // transfers ownership
|
||||
ddSizeLegend.setClasses( sizeClasses );
|
||||
|
||||
Q_FOREACH ( const QgsLegendSymbolItem &si, ddSizeLegend.legendSymbolList() )
|
||||
{
|
||||
if ( si.dataDefinedSizeLegendSettings() )
|
||||
nodes << new QgsDataDefinedSizeLegendNode( nodeLayer, *si.dataDefinedSizeLegendSettings() );
|
||||
else
|
||||
nodes << new QgsSymbolLegendNode( nodeLayer, si );
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
void QgsLinearlyInterpolatedDiagramRenderer::setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings )
|
||||
{
|
||||
mDataDefinedSizeLegend.reset( settings );
|
||||
}
|
||||
|
||||
QgsDataDefinedSizeLegend *QgsLinearlyInterpolatedDiagramRenderer::dataDefinedSizeLegend() const
|
||||
{
|
||||
return mDataDefinedSizeLegend.get();
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "qgspropertycollection.h"
|
||||
|
||||
|
||||
class QgsDataDefinedSizeLegend;
|
||||
class QgsDiagram;
|
||||
class QgsDiagramRenderer;
|
||||
class QgsFeature;
|
||||
@ -722,14 +723,31 @@ class CORE_EXPORT QgsLinearlyInterpolatedDiagramRenderer : public QgsDiagramRend
|
||||
|
||||
QList< QgsLayerTreeModelLegendNode * > legendItems( QgsLayerTreeLayer *nodeLayer ) const override SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Configures appearance of legend. Takes ownership of the passed settings objects.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings SIP_TRANSFER );
|
||||
|
||||
/**
|
||||
* Returns configuration of appearance of legend. Will return null if no configuration has been set.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
|
||||
|
||||
protected:
|
||||
bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const override;
|
||||
|
||||
QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c ) const override;
|
||||
|
||||
QgsLinearlyInterpolatedDiagramRenderer( const QgsLinearlyInterpolatedDiagramRenderer &other );
|
||||
|
||||
private:
|
||||
QgsDiagramSettings mSettings;
|
||||
QgsDiagramInterpolationSettings mInterpolationSettings;
|
||||
|
||||
//! Stores more settings about how legend for varying size of symbols should be rendered
|
||||
std::unique_ptr<QgsDataDefinedSizeLegend> mDataDefinedSizeLegend;
|
||||
};
|
||||
|
||||
#endif // QGSDIAGRAMRENDERERV2_H
|
||||
|
@ -196,8 +196,10 @@ QList<QgsLayerTreeModelLegendNode *> QgsDefaultVectorLayerLegend::createLayerTre
|
||||
|
||||
Q_FOREACH ( const QgsLegendSymbolItem &i, r->legendSymbolItems() )
|
||||
{
|
||||
QgsSymbolLegendNode *n = new QgsSymbolLegendNode( nodeLayer, i );
|
||||
nodes.append( n );
|
||||
if ( i.dataDefinedSizeLegendSettings() )
|
||||
nodes << new QgsDataDefinedSizeLegendNode( nodeLayer, *i.dataDefinedSizeLegendSettings() );
|
||||
else
|
||||
nodes << new QgsSymbolLegendNode( nodeLayer, i );
|
||||
}
|
||||
|
||||
if ( nodes.count() == 1 && nodes[0]->data( Qt::EditRole ).toString().isEmpty() )
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "qgscategorizedsymbolrenderer.h"
|
||||
|
||||
#include "qgsdatadefinedsizelegend.h"
|
||||
#include "qgssymbol.h"
|
||||
#include "qgssymbollayerutils.h"
|
||||
#include "qgscolorramp.h"
|
||||
@ -167,6 +168,10 @@ QgsCategorizedSymbolRenderer::QgsCategorizedSymbolRenderer( const QString &attrN
|
||||
}
|
||||
}
|
||||
|
||||
QgsCategorizedSymbolRenderer::~QgsCategorizedSymbolRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
void QgsCategorizedSymbolRenderer::rebuildHash()
|
||||
{
|
||||
mSymbolHash.clear();
|
||||
@ -653,6 +658,12 @@ QgsFeatureRenderer *QgsCategorizedSymbolRenderer::create( QDomElement &element,
|
||||
}
|
||||
}
|
||||
|
||||
QDomElement ddsLegendSizeElem = element.firstChildElement( "data-defined-size-legend" );
|
||||
if ( !ddsLegendSizeElem.isNull() )
|
||||
{
|
||||
r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readTypeAndAlignmentFromXml( ddsLegendSizeElem ) );
|
||||
}
|
||||
|
||||
// TODO: symbol levels
|
||||
return r;
|
||||
}
|
||||
@ -727,6 +738,13 @@ QDomElement QgsCategorizedSymbolRenderer::save( QDomDocument &doc, const QgsRead
|
||||
}
|
||||
rendererElem.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? "1" : "0" ) );
|
||||
|
||||
if ( mDataDefinedSizeLegend )
|
||||
{
|
||||
QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
|
||||
QgsDataDefinedSizeLegend::writeTypeAndAlignmentToXml( *mDataDefinedSizeLegend, ddsLegendElem );
|
||||
rendererElem.appendChild( ddsLegendElem );
|
||||
}
|
||||
|
||||
return rendererElem;
|
||||
}
|
||||
|
||||
@ -744,8 +762,7 @@ QgsLegendSymbolList QgsCategorizedSymbolRenderer::baseLegendSymbolItems() const
|
||||
|
||||
QgsLegendSymbolList QgsCategorizedSymbolRenderer::legendSymbolItems() const
|
||||
{
|
||||
QgsLegendSymbolList lst;
|
||||
if ( mSourceSymbol && mSourceSymbol->type() == QgsSymbol::Marker )
|
||||
if ( mDataDefinedSizeLegend && mSourceSymbol && mSourceSymbol->type() == QgsSymbol::Marker )
|
||||
{
|
||||
// check that all symbols that have the same size expression
|
||||
QgsProperty ddSize;
|
||||
@ -767,28 +784,15 @@ QgsLegendSymbolList QgsCategorizedSymbolRenderer::legendSymbolItems() const
|
||||
}
|
||||
}
|
||||
|
||||
if ( !ddSize || !ddSize.isActive() )
|
||||
if ( ddSize && ddSize.isActive() )
|
||||
{
|
||||
return baseLegendSymbolItems();
|
||||
}
|
||||
QgsLegendSymbolList lst;
|
||||
|
||||
if ( const QgsSizeScaleTransformer *sizeTransformer = dynamic_cast< const QgsSizeScaleTransformer * >( ddSize.transformer() ) )
|
||||
{
|
||||
QgsLegendSymbolItem title( nullptr, ddSize.propertyType() == QgsProperty::ExpressionBasedProperty ? ddSize.expressionString()
|
||||
: ddSize.field(), QString() );
|
||||
lst << title;
|
||||
Q_FOREACH ( double v, QgsSymbolLayerUtils::prettyBreaks( sizeTransformer->minValue(), sizeTransformer->maxValue(), 4 ) )
|
||||
{
|
||||
QgsLegendSymbolItem si( mSourceSymbol.get(), QString::number( v ), QString() );
|
||||
QgsMarkerSymbol *s = static_cast<QgsMarkerSymbol *>( si.symbol() );
|
||||
s->setDataDefinedSize( QgsProperty() );
|
||||
s->setSize( sizeTransformer->size( v ) );
|
||||
lst << si;
|
||||
}
|
||||
// now list the categorized symbols
|
||||
const QgsLegendSymbolList list2 = baseLegendSymbolItems();
|
||||
Q_FOREACH ( const QgsLegendSymbolItem &item, list2 )
|
||||
lst << item;
|
||||
QgsDataDefinedSizeLegend ddSizeLegend( *mDataDefinedSizeLegend );
|
||||
ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
|
||||
lst += ddSizeLegend.legendSymbolList();
|
||||
|
||||
lst += baseLegendSymbolItems();
|
||||
return lst;
|
||||
}
|
||||
}
|
||||
@ -942,3 +946,13 @@ QgsCategorizedSymbolRenderer *QgsCategorizedSymbolRenderer::convertFromRenderer(
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void QgsCategorizedSymbolRenderer::setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings )
|
||||
{
|
||||
mDataDefinedSizeLegend.reset( settings );
|
||||
}
|
||||
|
||||
QgsDataDefinedSizeLegend *QgsCategorizedSymbolRenderer::dataDefinedSizeLegend() const
|
||||
{
|
||||
return mDataDefinedSizeLegend.get();
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <QHash>
|
||||
|
||||
class QgsDataDefinedSizeLegend;
|
||||
class QgsVectorLayer;
|
||||
|
||||
/** \ingroup core
|
||||
@ -78,6 +79,7 @@ class CORE_EXPORT QgsCategorizedSymbolRenderer : public QgsFeatureRenderer
|
||||
public:
|
||||
|
||||
QgsCategorizedSymbolRenderer( const QString &attrName = QString(), const QgsCategoryList &categories = QgsCategoryList() );
|
||||
~QgsCategorizedSymbolRenderer();
|
||||
|
||||
virtual QgsSymbol *symbolForFeature( QgsFeature &feature, QgsRenderContext &context ) override;
|
||||
virtual QgsSymbol *originalSymbolForFeature( QgsFeature &feature, QgsRenderContext &context ) override;
|
||||
@ -179,6 +181,25 @@ class CORE_EXPORT QgsCategorizedSymbolRenderer : public QgsFeatureRenderer
|
||||
//! \returns a new renderer if the conversion was possible, otherwise 0.
|
||||
static QgsCategorizedSymbolRenderer *convertFromRenderer( const QgsFeatureRenderer *renderer ) SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Configures appearance of legend when renderer is configured to use data-defined size for marker symbols.
|
||||
* This allows to configure for what values (symbol sizes) should be shown in the legend, whether to display
|
||||
* different symbol sizes collapsed in one legend node or separated across multiple legend nodes etc.
|
||||
*
|
||||
* When renderer does not use data-defined size or does not use marker symbols, these settings will be ignored.
|
||||
* Takes ownership of the passed settings objects. Null pointer is a valid input that disables data-defined
|
||||
* size legend.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings SIP_TRANSFER );
|
||||
|
||||
/**
|
||||
* Returns configuration of appearance of legend when using data-defined size for marker symbols.
|
||||
* Will return null if the functionality is disabled.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
|
||||
|
||||
protected:
|
||||
QString mAttrName;
|
||||
QgsCategoryList mCategories;
|
||||
@ -186,6 +207,8 @@ class CORE_EXPORT QgsCategorizedSymbolRenderer : public QgsFeatureRenderer
|
||||
std::unique_ptr<QgsColorRamp> mSourceColorRamp;
|
||||
std::unique_ptr<QgsExpression> mExpression;
|
||||
|
||||
std::unique_ptr<QgsDataDefinedSizeLegend> mDataDefinedSizeLegend;
|
||||
|
||||
//! attribute index (derived from attribute name in startRender)
|
||||
int mAttrNum;
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "qgsattributes.h"
|
||||
#include "qgscolorramp.h"
|
||||
#include "qgsdatadefinedsizelegend.h"
|
||||
#include "qgsexpression.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsinvertedpolygonrenderer.h"
|
||||
@ -1037,6 +1038,13 @@ QgsFeatureRenderer *QgsGraduatedSymbolRenderer::create( QDomElement &element, co
|
||||
labelFormat.setFromDomElement( labelFormatElem );
|
||||
r->setLabelFormat( labelFormat );
|
||||
}
|
||||
|
||||
QDomElement ddsLegendSizeElem = element.firstChildElement( "data-defined-size-legend" );
|
||||
if ( !ddsLegendSizeElem.isNull() )
|
||||
{
|
||||
r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readTypeAndAlignmentFromXml( ddsLegendSizeElem ) );
|
||||
}
|
||||
|
||||
// TODO: symbol levels
|
||||
return r;
|
||||
}
|
||||
@ -1133,6 +1141,13 @@ QDomElement QgsGraduatedSymbolRenderer::save( QDomDocument &doc, const QgsReadWr
|
||||
}
|
||||
rendererElem.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? "1" : "0" ) );
|
||||
|
||||
if ( mDataDefinedSizeLegend )
|
||||
{
|
||||
QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
|
||||
QgsDataDefinedSizeLegend::writeTypeAndAlignmentToXml( *mDataDefinedSizeLegend, ddsLegendElem );
|
||||
rendererElem.appendChild( ddsLegendElem );
|
||||
}
|
||||
|
||||
return rendererElem;
|
||||
}
|
||||
|
||||
@ -1149,8 +1164,7 @@ QgsLegendSymbolList QgsGraduatedSymbolRenderer::baseLegendSymbolItems() const
|
||||
|
||||
QgsLegendSymbolList QgsGraduatedSymbolRenderer::legendSymbolItems() const
|
||||
{
|
||||
QgsLegendSymbolList list;
|
||||
if ( mSourceSymbol && mSourceSymbol->type() == QgsSymbol::Marker )
|
||||
if ( mDataDefinedSizeLegend && mSourceSymbol && mSourceSymbol->type() == QgsSymbol::Marker )
|
||||
{
|
||||
// check that all symbols that have the same size expression
|
||||
QgsProperty ddSize;
|
||||
@ -1172,29 +1186,16 @@ QgsLegendSymbolList QgsGraduatedSymbolRenderer::legendSymbolItems() const
|
||||
}
|
||||
}
|
||||
|
||||
if ( !ddSize || !ddSize.isActive() )
|
||||
if ( ddSize && ddSize.isActive() )
|
||||
{
|
||||
return baseLegendSymbolItems();
|
||||
}
|
||||
QgsLegendSymbolList lst;
|
||||
|
||||
if ( const QgsSizeScaleTransformer *sizeTransformer = dynamic_cast< const QgsSizeScaleTransformer * >( ddSize.transformer() ) )
|
||||
{
|
||||
QgsLegendSymbolItem title( nullptr, ddSize.propertyType() == QgsProperty::ExpressionBasedProperty ? ddSize.expressionString()
|
||||
: ddSize.field(), QString() );
|
||||
list << title;
|
||||
Q_FOREACH ( double v, QgsSymbolLayerUtils::prettyBreaks( sizeTransformer->minValue(), sizeTransformer->maxValue(), 4 ) )
|
||||
{
|
||||
QgsLegendSymbolItem si( mSourceSymbol.get(), QString::number( v ), QString() );
|
||||
QgsMarkerSymbol *s = static_cast<QgsMarkerSymbol *>( si.symbol() );
|
||||
s->setDataDefinedSize( QgsProperty() );
|
||||
s->setSize( sizeTransformer->size( v ) );
|
||||
list << si;
|
||||
}
|
||||
// now list the graduated symbols
|
||||
const QgsLegendSymbolList list2 = baseLegendSymbolItems();
|
||||
Q_FOREACH ( const QgsLegendSymbolItem &item, list2 )
|
||||
list << item;
|
||||
return list;
|
||||
QgsDataDefinedSizeLegend ddSizeLegend( *mDataDefinedSizeLegend );
|
||||
ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSourceSymbol.get() ), ddSize );
|
||||
lst += ddSizeLegend.legendSymbolList();
|
||||
|
||||
lst += baseLegendSymbolItems();
|
||||
return lst;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1623,6 +1624,16 @@ QgsGraduatedSymbolRenderer *QgsGraduatedSymbolRenderer::convertFromRenderer( con
|
||||
return r;
|
||||
}
|
||||
|
||||
void QgsGraduatedSymbolRenderer::setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings )
|
||||
{
|
||||
mDataDefinedSizeLegend.reset( settings );
|
||||
}
|
||||
|
||||
QgsDataDefinedSizeLegend *QgsGraduatedSymbolRenderer::dataDefinedSizeLegend() const
|
||||
{
|
||||
return mDataDefinedSizeLegend.get();
|
||||
}
|
||||
|
||||
const char *QgsGraduatedSymbolRenderer::graduatedMethodStr( GraduatedMethod method )
|
||||
{
|
||||
switch ( method )
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "qgsexpression.h"
|
||||
#include <QRegExp>
|
||||
|
||||
class QgsDataDefinedSizeLegend;
|
||||
|
||||
/** \ingroup core
|
||||
* \class QgsRendererRange
|
||||
*/
|
||||
@ -330,6 +332,25 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
//! \returns a new renderer if the conversion was possible, otherwise 0.
|
||||
static QgsGraduatedSymbolRenderer *convertFromRenderer( const QgsFeatureRenderer *renderer ) SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Configures appearance of legend when renderer is configured to use data-defined size for marker symbols.
|
||||
* This allows to configure for what values (symbol sizes) should be shown in the legend, whether to display
|
||||
* different symbol sizes collapsed in one legend node or separated across multiple legend nodes etc.
|
||||
*
|
||||
* When renderer does not use data-defined size or does not use marker symbols, these settings will be ignored.
|
||||
* Takes ownership of the passed settings objects. Null pointer is a valid input that disables data-defined
|
||||
* size legend.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings SIP_TRANSFER );
|
||||
|
||||
/**
|
||||
* Returns configuration of appearance of legend when using data-defined size for marker symbols.
|
||||
* Will return null if the functionality is disabled.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
|
||||
|
||||
protected:
|
||||
QString mAttrName;
|
||||
QgsRangeList mRanges;
|
||||
@ -344,6 +365,8 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer
|
||||
int mAttrNum;
|
||||
bool mCounting;
|
||||
|
||||
std::unique_ptr<QgsDataDefinedSizeLegend> mDataDefinedSizeLegend;
|
||||
|
||||
QgsSymbol *symbolForValue( double value );
|
||||
|
||||
/** Returns the matching legend key for a value.
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "qgslegendsymbolitem.h"
|
||||
|
||||
#include "qgsdatadefinedsizelegend.h"
|
||||
#include "qgssymbol.h"
|
||||
|
||||
QgsLegendSymbolItem::QgsLegendSymbolItem()
|
||||
@ -61,6 +62,7 @@ QgsLegendSymbolItem &QgsLegendSymbolItem::operator=( const QgsLegendSymbolItem &
|
||||
mLabel = other.mLabel;
|
||||
mKey = other.mKey;
|
||||
mCheckable = other.mCheckable;
|
||||
mDataDefinedSizeLegendSettings.reset( other.mDataDefinedSizeLegendSettings.get() ? new QgsDataDefinedSizeLegend( *other.mDataDefinedSizeLegendSettings.get() ) : nullptr );
|
||||
mOriginalSymbolPointer = other.mOriginalSymbolPointer;
|
||||
mScaleMinDenom = other.mScaleMinDenom;
|
||||
mScaleMaxDenom = other.mScaleMaxDenom;
|
||||
@ -89,3 +91,13 @@ void QgsLegendSymbolItem::setSymbol( QgsSymbol *s )
|
||||
mSymbol = s ? s->clone() : nullptr;
|
||||
mOriginalSymbolPointer = s;
|
||||
}
|
||||
|
||||
void QgsLegendSymbolItem::setDataDefinedSizeLegendSettings( QgsDataDefinedSizeLegend *settings )
|
||||
{
|
||||
mDataDefinedSizeLegendSettings.reset( settings );
|
||||
}
|
||||
|
||||
QgsDataDefinedSizeLegend *QgsLegendSymbolItem::dataDefinedSizeLegendSettings() const
|
||||
{
|
||||
return mDataDefinedSizeLegendSettings.get();
|
||||
}
|
||||
|
@ -16,11 +16,13 @@
|
||||
#ifndef QGSLEGENDSYMBOLITEMV2_H
|
||||
#define QGSLEGENDSYMBOLITEMV2_H
|
||||
|
||||
#include <memory>
|
||||
#include <QString>
|
||||
#include "qgis.h"
|
||||
|
||||
#include "qgis_core.h"
|
||||
|
||||
class QgsDataDefinedSizeLegend;
|
||||
class QgsSymbol;
|
||||
|
||||
/** \ingroup core
|
||||
@ -72,6 +74,21 @@ class CORE_EXPORT QgsLegendSymbolItem
|
||||
//! Set symbol of the item. Takes ownership of symbol.
|
||||
void setSymbol( QgsSymbol *s SIP_TRANSFER );
|
||||
|
||||
/**
|
||||
* Sets extra information about data-defined size. If set, this item should be converted to QgsDataDefinedSizeLegendNode
|
||||
* rather than QgsSymbolLegendNode instance as usual. Passing null removes any data-defined size legend settings.
|
||||
*
|
||||
* Takes ownership of the settings object.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
void setDataDefinedSizeLegendSettings( QgsDataDefinedSizeLegend *settings SIP_TRANSFER );
|
||||
|
||||
/**
|
||||
* Returns extra information for data-defined size legend rendering. Normally it returns null.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsDataDefinedSizeLegend *dataDefinedSizeLegendSettings() const;
|
||||
|
||||
private:
|
||||
//! symbol. owned by the struct. can be null.
|
||||
QgsSymbol *mSymbol = nullptr;
|
||||
@ -84,6 +101,10 @@ class CORE_EXPORT QgsLegendSymbolItem
|
||||
|
||||
QgsSymbol *mOriginalSymbolPointer = nullptr;
|
||||
|
||||
//! optional pointer to data-defined legend size settings - if set, the output legend
|
||||
//! node should be QgsDataDefinedSizeLegendNode rather than ordinary QgsSymbolLegendNode
|
||||
std::unique_ptr<QgsDataDefinedSizeLegend> mDataDefinedSizeLegendSettings;
|
||||
|
||||
// additional data that may be used for filtering
|
||||
|
||||
int mScaleMinDenom;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "qgssymbol.h"
|
||||
#include "qgssymbollayerutils.h"
|
||||
|
||||
#include "qgsdatadefinedsizelegend.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
@ -39,6 +40,10 @@ QgsSingleSymbolRenderer::QgsSingleSymbolRenderer( QgsSymbol *symbol )
|
||||
Q_ASSERT( symbol );
|
||||
}
|
||||
|
||||
QgsSingleSymbolRenderer::~QgsSingleSymbolRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
QgsSymbol *QgsSingleSymbolRenderer::symbolForFeature( QgsFeature &, QgsRenderContext & )
|
||||
{
|
||||
return mSymbol.get();
|
||||
@ -154,6 +159,12 @@ QgsFeatureRenderer *QgsSingleSymbolRenderer::create( QDomElement &element, const
|
||||
sizeScaleElem.attribute( QStringLiteral( "field" ) ) );
|
||||
}
|
||||
|
||||
QDomElement ddsLegendSizeElem = element.firstChildElement( "data-defined-size-legend" );
|
||||
if ( !ddsLegendSizeElem.isNull() )
|
||||
{
|
||||
r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readTypeAndAlignmentFromXml( ddsLegendSizeElem ) );
|
||||
}
|
||||
|
||||
// TODO: symbol levels
|
||||
return r;
|
||||
}
|
||||
@ -275,33 +286,28 @@ QDomElement QgsSingleSymbolRenderer::save( QDomDocument &doc, const QgsReadWrite
|
||||
}
|
||||
rendererElem.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? "1" : "0" ) );
|
||||
|
||||
if ( mDataDefinedSizeLegend )
|
||||
{
|
||||
QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
|
||||
QgsDataDefinedSizeLegend::writeTypeAndAlignmentToXml( *mDataDefinedSizeLegend, ddsLegendElem );
|
||||
rendererElem.appendChild( ddsLegendElem );
|
||||
}
|
||||
|
||||
return rendererElem;
|
||||
}
|
||||
|
||||
QgsLegendSymbolList QgsSingleSymbolRenderer::legendSymbolItems() const
|
||||
{
|
||||
QgsLegendSymbolList lst;
|
||||
if ( mSymbol->type() == QgsSymbol::Marker )
|
||||
if ( mDataDefinedSizeLegend && mSymbol->type() == QgsSymbol::Marker )
|
||||
{
|
||||
const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( mSymbol.get() );
|
||||
QgsProperty sizeDD( symbol->dataDefinedSize() );
|
||||
if ( sizeDD && sizeDD.isActive() )
|
||||
{
|
||||
if ( const QgsSizeScaleTransformer *sizeTransformer = dynamic_cast< const QgsSizeScaleTransformer * >( sizeDD.transformer() ) )
|
||||
{
|
||||
QgsLegendSymbolItem title( nullptr, sizeDD.propertyType() == QgsProperty::ExpressionBasedProperty ? sizeDD.expressionString()
|
||||
: sizeDD.field(), QString() );
|
||||
lst << title;
|
||||
Q_FOREACH ( double v, QgsSymbolLayerUtils::prettyBreaks( sizeTransformer->minValue(), sizeTransformer->maxValue(), 4 ) )
|
||||
{
|
||||
QgsLegendSymbolItem si( mSymbol.get(), QString::number( v ), QString() );
|
||||
QgsMarkerSymbol *s = static_cast<QgsMarkerSymbol *>( si.symbol() );
|
||||
s->setDataDefinedSize( QgsProperty() );
|
||||
s->setSize( sizeTransformer->size( v ) );
|
||||
lst << si;
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
QgsDataDefinedSizeLegend ddSizeLegend( *mDataDefinedSizeLegend );
|
||||
ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSymbol.get() ), sizeDD );
|
||||
lst += ddSizeLegend.legendSymbolList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -360,3 +366,13 @@ QgsSingleSymbolRenderer *QgsSingleSymbolRenderer::convertFromRenderer( const Qgs
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void QgsSingleSymbolRenderer::setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings )
|
||||
{
|
||||
mDataDefinedSizeLegend.reset( settings );
|
||||
}
|
||||
|
||||
QgsDataDefinedSizeLegend *QgsSingleSymbolRenderer::dataDefinedSizeLegend() const
|
||||
{
|
||||
return mDataDefinedSizeLegend.get();
|
||||
}
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "qgssymbol.h"
|
||||
#include "qgsexpression.h"
|
||||
|
||||
class QgsDataDefinedSizeLegend;
|
||||
|
||||
/** \ingroup core
|
||||
* \class QgsSingleSymbolRenderer
|
||||
*/
|
||||
@ -29,6 +31,7 @@ class CORE_EXPORT QgsSingleSymbolRenderer : public QgsFeatureRenderer
|
||||
public:
|
||||
|
||||
QgsSingleSymbolRenderer( QgsSymbol *symbol SIP_TRANSFER );
|
||||
~QgsSingleSymbolRenderer();
|
||||
|
||||
virtual QgsSymbol *symbolForFeature( QgsFeature &feature, QgsRenderContext &context ) override;
|
||||
virtual QgsSymbol *originalSymbolForFeature( QgsFeature &feature, QgsRenderContext &context ) override;
|
||||
@ -61,8 +64,28 @@ class CORE_EXPORT QgsSingleSymbolRenderer : public QgsFeatureRenderer
|
||||
//! \returns a new renderer if the conversion was possible, otherwise 0.
|
||||
static QgsSingleSymbolRenderer *convertFromRenderer( const QgsFeatureRenderer *renderer ) SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Configures appearance of legend when renderer is configured to use data-defined size for marker symbols.
|
||||
* This allows to configure for what values (symbol sizes) should be shown in the legend, whether to display
|
||||
* different symbol sizes collapsed in one legend node or separated across multiple legend nodes etc.
|
||||
*
|
||||
* When renderer does not use data-defined size or does not use marker symbols, these settings will be ignored.
|
||||
* Takes ownership of the passed settings objects. Null pointer is a valid input that disables data-defined
|
||||
* size legend.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings SIP_TRANSFER );
|
||||
|
||||
/**
|
||||
* Returns configuration of appearance of legend when using data-defined size for marker symbols.
|
||||
* Will return null if the functionality is disabled.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<QgsSymbol> mSymbol;
|
||||
std::unique_ptr<QgsDataDefinedSizeLegend> mDataDefinedSizeLegend;
|
||||
|
||||
private:
|
||||
#ifdef SIP_RUN
|
||||
|
Loading…
x
Reference in New Issue
Block a user