Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FEATURE][diagrams] Add option to show diagram axis for histogram dia…
…gram symbols

Where the axis line symbol can be set using a standard QGIS line symbol.

Sponsored by SLYR
  • Loading branch information
nyalldawson committed Nov 23, 2019
1 parent 6db6ede commit 9a23e1b
Show file tree
Hide file tree
Showing 11 changed files with 490 additions and 112 deletions.
52 changes: 52 additions & 0 deletions python/core/auto_generated/qgsdiagramrenderer.sip.in
Expand Up @@ -377,6 +377,12 @@ QgsDiagramLayerSettings stores settings which control how ALL diagrams within a
Constructor for QgsDiagramSettings
%End

QgsDiagramSettings( const QgsDiagramSettings &other );
%Docstring
Copy constructor
%End


bool enabled;
QFont font;
QList< QColor > categoryColors;
Expand Down Expand Up @@ -531,6 +537,52 @@ Returns list of legend nodes for the diagram
caller is responsible for deletion of :py:class:`QgsLayerTreeModelLegendNodes`

.. versionadded:: 2.10
%End

QgsLineSymbol *axisLineSymbol() const;
%Docstring
Returns the line symbol to use for rendering axis in diagrams.

.. seealso:: :py:func:`setAxisLineSymbol`

.. seealso:: :py:func:`showAxis`

.. versionadded:: 3.12
%End

void setAxisLineSymbol( QgsLineSymbol *symbol /Transfer/ );
%Docstring
Sets the line ``symbol`` to use for rendering axis in diagrams.

Ownership of ``symbol`` is transferred to the settings.

.. seealso:: :py:func:`axisLineSymbol`

.. seealso:: :py:func:`setShowAxis`

.. versionadded:: 3.12
%End

bool showAxis() const;
%Docstring
Returns ``True`` if the diagram axis should be shown.

.. seealso:: :py:func:`setShowAxis`

.. seealso:: :py:func:`axisLineSymbol`

.. versionadded:: 3.12
%End

void setShowAxis( bool showAxis );
%Docstring
Sets whether the diagram axis should be shown.

.. seealso:: :py:func:`showAxis`

.. seealso:: :py:func:`setAxisLineSymbol`

.. versionadded:: 3.12
%End

};
Expand Down
12 changes: 12 additions & 0 deletions src/app/qgsdiagramproperties.cpp
Expand Up @@ -101,6 +101,9 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
mDiagramTypeComboBox->addItem( pix, tr( "Histogram" ), DIAGRAM_NAME_HISTOGRAM );
mDiagramTypeComboBox->blockSignals( false );

mAxisLineStyleButton->setSymbolType( QgsSymbol::Line );
mAxisLineStyleButton->setDialogTitle( tr( "Axis Line Symbol" ) );

mScaleRangeWidget->setMapCanvas( mMapCanvas );
mSizeFieldExpressionWidget->registerExpressionContextGenerator( this );

Expand Down Expand Up @@ -354,6 +357,10 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
mBarSpacingUnitComboBox->setUnit( settingList.at( 0 ).spacingUnit() );
mBarSpacingUnitComboBox->setMapUnitScale( settingList.at( 0 ).spacingMapUnitScale() );

mShowAxisGroupBox->setChecked( settingList.at( 0 ).showAxis() );
if ( settingList.at( 0 ).axisLineSymbol() )
mAxisLineStyleButton->setSymbol( settingList.at( 0 ).axisLineSymbol()->clone() );

mIncreaseSmallDiagramsCheck->setChecked( settingList.at( 0 ).minimumSize != 0 );
mIncreaseMinimumSizeSpinBox->setEnabled( mIncreaseSmallDiagramsCheck->isChecked() );
mIncreaseMinimumSizeLabel->setEnabled( mIncreaseSmallDiagramsCheck->isChecked() );
Expand Down Expand Up @@ -550,6 +557,7 @@ void QgsDiagramProperties::mDiagramTypeComboBox_currentIndexChanged( int index )
mBarSpacingSpinBox->show();
mBarSpacingUnitComboBox->show();
mBarOptionsFrame->show();
mShowAxisGroupBox->show();
mAttributeBasedScalingRadio->setChecked( true );
mFixedSizeRadio->setEnabled( false );
mDiagramSizeSpinBox->setEnabled( false );
Expand All @@ -564,6 +572,7 @@ void QgsDiagramProperties::mDiagramTypeComboBox_currentIndexChanged( int index )
mBarSpacingLabel->hide();
mBarSpacingSpinBox->hide();
mBarSpacingUnitComboBox->hide();
mShowAxisGroupBox->hide();
mBarOptionsFrame->hide();
mLinearlyScalingLabel->setText( tr( "Scale linearly between 0 and the following attribute value / diagram size:" ) );
mSizeLabel->setText( tr( "Size" ) );
Expand Down Expand Up @@ -817,6 +826,9 @@ void QgsDiagramProperties::apply()

ds.barWidth = mBarWidthSpinBox->value();

ds.setAxisLineSymbol( mAxisLineStyleButton->clonedSymbol< QgsLineSymbol >() );
ds.setShowAxis( mShowAxisGroupBox->isChecked() );

ds.setSpacing( mBarSpacingSpinBox->value() );
ds.setSpacingUnit( mBarSpacingUnitComboBox->unit() );
ds.setSpacingMapUnitScale( mBarSpacingUnitComboBox->getMapUnitScale() );
Expand Down
56 changes: 56 additions & 0 deletions src/core/diagram/qgshistogramdiagram.cpp
Expand Up @@ -16,6 +16,7 @@
#include "qgsdiagramrenderer.h"
#include "qgsrendercontext.h"
#include "qgsexpression.h"
#include "qgssymbollayerutils.h"

#include <QPainter>

Expand Down Expand Up @@ -83,6 +84,13 @@ QSizeF QgsHistogramDiagram::diagramSize( const QgsFeature &feature, const QgsRen
break;
}

if ( s.showAxis() && s.axisLineSymbol() )
{
const double maxBleed = QgsSymbolLayerUtils::estimateMaxSymbolBleed( s.axisLineSymbol(), c ) / painterUnitConversionScale;
size.setWidth( size.width() + 2 * maxBleed );
size.setHeight( size.height() + 2 * maxBleed );
}

return size;
}

Expand Down Expand Up @@ -145,6 +153,13 @@ QSizeF QgsHistogramDiagram::diagramSize( const QgsAttributes &attributes, const
break;
}

if ( s.showAxis() && s.axisLineSymbol() )
{
const double maxBleed = QgsSymbolLayerUtils::estimateMaxSymbolBleed( s.axisLineSymbol(), c ) / painterUnitConversionScale;
size.setWidth( size.width() + 2 * maxBleed );
size.setHeight( size.height() + 2 * maxBleed );
}

return size;
}

Expand Down Expand Up @@ -183,6 +198,16 @@ void QgsHistogramDiagram::renderDiagram( const QgsFeature &feature, QgsRenderCon
double baseX = position.x();
double baseY = position.y();

if ( s.showAxis() && s.axisLineSymbol() )
{
// if showing axis, the diagram position needs shifting from the default base x so that the axis
// line stroke sits within the desired label engine rect (otherwise we risk overlaps of the axis line stroke)
const double maxBleed = QgsSymbolLayerUtils::estimateMaxSymbolBleed( s.axisLineSymbol(), c );
baseX += maxBleed;
baseY -= maxBleed;
}


mPen.setColor( s.penColor );
setPenWidth( mPen, s, c );
p->setPen( mPen );
Expand Down Expand Up @@ -217,4 +242,35 @@ void QgsHistogramDiagram::renderDiagram( const QgsFeature &feature, QgsRenderCon

currentOffset += scaledWidth + spacing;
}

if ( s.showAxis() && s.axisLineSymbol() )
{
s.axisLineSymbol()->startRender( c );
QPolygonF axisPoints;
switch ( s.diagramOrientation )
{
case QgsDiagramSettings::Up:
axisPoints << QPointF( baseX, baseY - scaledMaxVal ) << QPointF( baseX, baseY ) << QPointF( baseX + scaledWidth * values.size() + spacing * std::max( 0, values.size() - 1 ), baseY );
break;

case QgsDiagramSettings::Down:
axisPoints << QPointF( baseX, baseY ) << QPointF( baseX, baseY - scaledMaxVal ) << QPointF( baseX + scaledWidth * values.size() + spacing * std::max( 0, values.size() - 1 ), baseY - scaledMaxVal );
break;

case QgsDiagramSettings::Right:
axisPoints << QPointF( baseX + scaledMaxVal, baseY - scaledWidth * values.size() - spacing * std::max( 0, values.size() - 1 ) )
<< QPointF( baseX, baseY - scaledWidth * values.size() - spacing * std::max( 0, values.size() - 1 ) )
<< QPointF( baseX, baseY );
break;

case QgsDiagramSettings::Left:
axisPoints << QPointF( baseX, baseY - scaledWidth * values.size() - spacing * std::max( 0, values.size() - 1 ) )
<< QPointF( baseX + scaledMaxVal, baseY - scaledWidth * values.size() - spacing * std::max( 0, values.size() - 1 ) )
<< QPointF( baseX + scaledMaxVal, baseY );
break;
}

s.axisLineSymbol()->renderPolyline( axisPoints, nullptr, c );
s.axisLineSymbol()->stopRender( c );
}
}
114 changes: 114 additions & 0 deletions src/core/qgsdiagramrenderer.cpp
Expand Up @@ -272,10 +272,24 @@ void QgsDiagramSettings::readXml( const QDomElement &elem, const QgsReadWriteCon

minimumSize = elem.attribute( QStringLiteral( "minimumSize" ) ).toDouble();

QDomNodeList axisSymbolNodes = elem.elementsByTagName( QStringLiteral( "axisSymbol" ) );
if ( axisSymbolNodes.count() > 0 )
{
QDomElement axisSymbolElem = axisSymbolNodes.at( 0 ).toElement().firstChildElement();
mAxisLineSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( axisSymbolElem, context ) );
}
else
{
mAxisLineSymbol = qgis::make_unique< QgsLineSymbol >();
}

mShowAxis = elem.attribute( QStringLiteral( "showAxis" ), QStringLiteral( "0" ) ).toInt();

//colors
categoryColors.clear();
QDomNodeList attributes = elem.elementsByTagName( QStringLiteral( "attribute" ) );


if ( attributes.length() > 0 )
{
for ( int i = 0; i < attributes.size(); i++ )
Expand Down Expand Up @@ -404,6 +418,12 @@ void QgsDiagramSettings::writeXml( QDomElement &rendererElem, QDomDocument &doc,
categoryElem.appendChild( attributeElem );
}

categoryElem.setAttribute( QStringLiteral( "showAxis" ), mShowAxis ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
QDomElement axisSymbolElem = doc.createElement( QStringLiteral( "axisSymbol" ) );
QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QString(), mAxisLineSymbol.get(), doc, context );
axisSymbolElem.appendChild( symbolElem );
categoryElem.appendChild( axisSymbolElem );

rendererElem.appendChild( categoryElem );
}

Expand Down Expand Up @@ -761,6 +781,100 @@ QList< QgsLayerTreeModelLegendNode * > QgsDiagramSettings::legendItems( QgsLayer
return list;
}

QgsLineSymbol *QgsDiagramSettings::axisLineSymbol() const
{
return mAxisLineSymbol.get();
}

void QgsDiagramSettings::setAxisLineSymbol( QgsLineSymbol *axisLineSymbol )
{
if ( axisLineSymbol != mAxisLineSymbol.get() )
mAxisLineSymbol.reset( axisLineSymbol );
}

bool QgsDiagramSettings::showAxis() const
{
return mShowAxis;
}

void QgsDiagramSettings::setShowAxis( bool showAxis )
{
mShowAxis = showAxis;
}

QgsDiagramSettings::QgsDiagramSettings()
: mAxisLineSymbol( qgis::make_unique< QgsLineSymbol >() )
{
}

QgsDiagramSettings::QgsDiagramSettings( const QgsDiagramSettings &other )
: enabled( other.enabled )
, font( other.font )
, categoryColors( other.categoryColors )
, categoryAttributes( other.categoryAttributes )
, categoryLabels( other.categoryLabels )
, size( other.size )
, sizeType( other.sizeType )
, sizeScale( other.sizeScale )
, lineSizeUnit( other.lineSizeUnit )
, lineSizeScale( other.lineSizeScale )
, backgroundColor( other.backgroundColor )
, penColor( other.penColor )
, penWidth( other.penWidth )
, labelPlacementMethod( other.labelPlacementMethod )
, diagramOrientation( other.diagramOrientation )
, barWidth( other.barWidth )
, opacity( other.opacity )
, scaleByArea( other.scaleByArea )
, rotationOffset( other.rotationOffset )
, scaleBasedVisibility( other.scaleBasedVisibility )
, maximumScale( other.maximumScale )
, minimumScale( other.minimumScale )
, minimumSize( other.minimumSize )
, mSpacing( other.mSpacing )
, mSpacingUnit( other.mSpacingUnit )
, mSpacingMapUnitScale( other.mSpacingMapUnitScale )
, mDirection( other.mDirection )
, mShowAxis( other.mShowAxis )
, mAxisLineSymbol( other.mAxisLineSymbol ? other.mAxisLineSymbol->clone() : nullptr )
{

}

QgsDiagramSettings &QgsDiagramSettings::operator=( const QgsDiagramSettings &other )
{
enabled = other.enabled;
font = other.font;
categoryColors = other.categoryColors;
categoryAttributes = other.categoryAttributes;
categoryLabels = other.categoryLabels;
size = other.size;
sizeType = other.sizeType;
sizeScale = other.sizeScale;
lineSizeUnit = other.lineSizeUnit;
lineSizeScale = other.lineSizeScale;
backgroundColor = other.backgroundColor;
penColor = other.penColor;
penWidth = other.penWidth;
labelPlacementMethod = other.labelPlacementMethod;
diagramOrientation = other.diagramOrientation;
barWidth = other.barWidth;
opacity = other.opacity;
scaleByArea = other.scaleByArea;
rotationOffset = other.rotationOffset;
scaleBasedVisibility = other.scaleBasedVisibility;
maximumScale = other.maximumScale;
minimumScale = other.minimumScale;
minimumSize = other.minimumSize;
mSpacing = other.mSpacing;
mSpacingUnit = other.mSpacingUnit;
mSpacingMapUnitScale = other.mSpacingMapUnitScale;
mDirection = other.mDirection;
mAxisLineSymbol.reset( other.mAxisLineSymbol ? other.mAxisLineSymbol->clone() : nullptr );
mShowAxis = other.mShowAxis;
return *this;
}

QgsDiagramSettings::Direction QgsDiagramSettings::direction() const
{
return mDirection;
Expand Down

0 comments on commit 9a23e1b

Please sign in to comment.