Support more than one data point in a diagram

This commit is contained in:
Peter Hartmann 2021-04-16 16:11:09 +02:00
parent d4bc4e12f5
commit ad03c0f6a0
8 changed files with 142 additions and 72 deletions

View File

@ -9,17 +9,21 @@ class Diagram::PrivateData
{
}
QVector<QPointF> dataPoints;
QVector<QVector<QPointF> > dataPoints;
int xGridLines = -1;
qreal yMax = -1;
Qsk::Position position = Qsk::Bottom;
Types types = Area;
QVector<Types> types;
};
QSK_SUBCONTROL( Diagram, Chart )
QSK_SUBCONTROL( Diagram, Segments )
QSK_SUBCONTROL( Diagram, ChartLine )
QSK_SUBCONTROL( Diagram, ChartArea )
QSK_SUBCONTROL( Diagram, ChartLine1 )
QSK_SUBCONTROL( Diagram, ChartArea1 )
QSK_SUBCONTROL( Diagram, ChartLine2 )
QSK_SUBCONTROL( Diagram, ChartArea2 )
QSK_SUBCONTROL( Diagram, ChartLine3 )
QSK_SUBCONTROL( Diagram, ChartArea3 )
Diagram::Diagram( QQuickItem* parent )
: Inherited( parent )
@ -31,24 +35,20 @@ Diagram::~Diagram()
{
}
QVector<QPointF> Diagram::dataPoints() const
QVector< QVector<QPointF> > Diagram::dataPoints() const
{
return m_data->dataPoints;
}
void Diagram::setDataPoints( const QVector<QPointF>& dataPoints )
void Diagram::addDataPoints( const QVector<QPointF>& dataPoints, const Types& types )
{
m_data->dataPoints = dataPoints;
m_data->dataPoints.append( dataPoints );
m_data->types.append( types );
}
Diagram::Types Diagram::types() const
Diagram::Types Diagram::typesAt( uint pos ) const
{
return m_data->types;
}
void Diagram::setTypes( Types types )
{
m_data->types = types;
return m_data->types.at( pos );
}
qreal Diagram::yMax() const

View File

@ -12,7 +12,7 @@ class Diagram : public QskControl
using Inherited = QskControl;
public:
QSK_SUBCONTROLS( Chart, Segments, ChartLine, ChartArea )
QSK_SUBCONTROLS( Chart, Segments, ChartLine1, ChartArea1, ChartLine2, ChartArea2, ChartLine3, ChartArea3 )
enum Type
{
@ -25,11 +25,10 @@ class Diagram : public QskControl
Diagram( QQuickItem* parent = nullptr );
~Diagram() override;
QVector<QPointF> dataPoints() const;
void setDataPoints( const QVector<QPointF>& dataPoints );
QVector< QVector<QPointF> > dataPoints() const;
void addDataPoints( const QVector<QPointF>& dataPoints, const Types& types );
Types types() const;
void setTypes( Types types );
Types typesAt( uint pos ) const;
qreal yMax() const;
void setYMax( qreal yMax );

View File

@ -3,6 +3,39 @@
#include "nodes/DiagramDataNode.h"
#include "nodes/DiagramSegmentsNode.h"
namespace
{
QskAspect::Subcontrol areaForIndex( int i )
{
switch( i )
{
case 1:
return Diagram::ChartArea2;
case 2:
return Diagram::ChartArea3;
default:
return Diagram::ChartArea1;
}
}
QskAspect::Subcontrol lineForIndex( int i )
{
switch( i )
{
case 1:
return Diagram::ChartLine2;
case 2:
return Diagram::ChartLine3;
default:
return Diagram::ChartLine1;
}
}
}
DiagramSkinlet::DiagramSkinlet( QskSkin* skin )
: QskSkinlet( skin )
{
@ -46,59 +79,78 @@ QSGNode* DiagramSkinlet::updateSubNode(
return nullptr;
}
QSGNode* DiagramSkinlet::updateChartNode( const Diagram* distribution, QSGNode* node ) const
QSGNode* DiagramSkinlet::updateChartNode( const Diagram* diagram, QSGNode* node ) const
{
if( node == nullptr )
{
node = new IdlChartNode;
node = new IdlChartNode; // ### rename
}
using Q = Diagram;
const QRectF rect = distribution->subControlRect( Q::Chart );
const QVector<QPointF> dataPoints = distribution->dataPoints();
const qreal yMax = distribution->yMax();
const Qsk::Position position = distribution->chartPosition();
int lineWidth = distribution->metric( Diagram::ChartLine | QskAspect::Size );
const QRectF rect = diagram->subControlRect( Q::Chart );
const qreal yMax = diagram->yMax();
const Qsk::Position position = diagram->chartPosition();
QVector<Diagram::Type> types = {Diagram::Line, Diagram::Area};
int nodeIndex = 0;
for( int i = 0; i < diagram->dataPoints().size(); ++i )
{
QSGNode* chartNode;
for( int i = 0; i < types.size(); ++i )
if( node->childCount() > i )
{
if( distribution->types() & types.at( i ) )
{
IdlChartNode* lineNode;
if( node->childCount() > nodeIndex )
{
lineNode = static_cast<IdlChartNode*>( node->childAtIndex( nodeIndex ) );
chartNode = node->childAtIndex( i );
}
else
{
lineNode = new IdlChartNode;
node->appendChildNode( lineNode );
chartNode = new QSGNode;
node->appendChildNode( chartNode );
}
const IdlChartNode::Type nodeType = ( types.at( i ) == Diagram::Line ) ? IdlChartNode::Line : IdlChartNode::Area;
const QColor color = ( types.at( i ) == Diagram::Line ) ? distribution->color( Q::ChartLine )
: distribution->color( Q::ChartArea );
const QVector<QPointF> dataPoints = diagram->dataPoints().at( i );
int nodeIndex = 0;
QskAspect::Subcontrol lineSubcontrol = lineForIndex( i );
QskAspect::Subcontrol areaSubcontrol = areaForIndex( i );
int lineWidth = diagram->metric( lineSubcontrol | QskAspect::Size );
lineNode->update( rect, nodeType, color, dataPoints, yMax, position, lineWidth );
for( int j = 0; j < types.size(); ++j )
{
if( diagram->typesAt( i ) & types.at( j ) )
{
IdlChartNode* dataPointNode;
if( chartNode->childCount() > nodeIndex )
{
dataPointNode = static_cast<IdlChartNode*>( chartNode->childAtIndex( nodeIndex ) );
}
else
{
dataPointNode = new IdlChartNode;
chartNode->appendChildNode( dataPointNode );
}
const IdlChartNode::Type nodeType = ( types.at( j ) == Diagram::Line ) ? IdlChartNode::Line : IdlChartNode::Area;
const QColor color = ( types.at( j ) == Diagram::Line ) ? diagram->color( lineSubcontrol )
: diagram->color( areaSubcontrol );
dataPointNode->update( rect, nodeType, color, dataPoints, yMax, position, lineWidth );
nodeIndex++;
}
}
while( nodeIndex < node->childCount() )
while( nodeIndex < chartNode->childCount() )
{
node->removeChildNode( node->childAtIndex( nodeIndex++ ) );
chartNode->removeChildNode( chartNode->childAtIndex( nodeIndex++ ) );
}
}
// ### also check for superfluous nodes here
return node;
}
QSGNode* DiagramSkinlet::updateSeparatorNode( const Diagram* discharge, QSGNode* node ) const
QSGNode* DiagramSkinlet::updateSeparatorNode( const Diagram* diagram, QSGNode* node ) const
{
const int xGridLines = discharge->xGridLines();
const int xGridLines = diagram->xGridLines();
if( xGridLines <= 0 )
{
@ -113,9 +165,9 @@ QSGNode* DiagramSkinlet::updateSeparatorNode( const Diagram* discharge, QSGNode*
}
using Q = Diagram;
const QRectF rect = discharge->subControlRect( Q::Chart );
const QColor color = discharge->color( Q::Segments );
const QVector<QPointF> dataPoints = discharge->dataPoints();
const QRectF rect = diagram->subControlRect( Q::Chart );
const QColor color = diagram->color( Q::Segments );
const QVector< QVector<QPointF> > dataPoints = diagram->dataPoints();
separatorNode->update( rect, color, dataPoints, xGridLines );

View File

@ -156,8 +156,9 @@ void Skin::initHints( const Palette& palette )
// new diagram:
ed.setMetric( Diagram::ChartLine | QskAspect::Size, 2 );
ed.setColor( Diagram::ChartArea, "#886776ff" );
ed.setColor( Diagram::ChartArea1, "#886776ff" );
ed.setColor( Diagram::ChartArea2, "#88ff3122" );
ed.setColor( Diagram::ChartArea3, "#88ff7d34" );
// light intensity:
@ -178,7 +179,6 @@ void Skin::initHints( const Palette& palette )
ed.setGradient( RoundButton::Panel, palette.roundButton );
ed.setBoxBorderColors( WeekdayBox::Panel, palette.weekdayBox );
ed.setColor( QskTextLabel::Text, palette.text );
ed.setColor( Diagram::ChartLine, Qt::transparent );
ed.setColor( WeekdayLabel::Text, palette.text );
ed.setColor( ShadowPositioner::Panel, palette.shadow );
}

View File

@ -70,23 +70,33 @@ UsageDiagram::UsageDiagram( QQuickItem* parent )
setAutoAddChildren( false );
setAutoLayoutChildren( true );
m_diagram->setTypes( Diagram::Line | Diagram::Area );
m_diagram->setChartPosition( Qsk::Bottom );
int number = 100;
QVector<QPointF> dataPoints1;
dataPoints1.reserve( number );
std::vector<qreal> yValues1 = {40, 20, 30, 50, 30, 70, 80, 100, 90, 60};
qreal t0 = yValues1[0];
std::vector< std::vector<qreal> > yValues =
{
{40, 20, 30, 50, 30, 70, 80, 100, 90, 60},
{15, 70, 40, 60, 10, 90, 20, 40, 45, 50},
{70, 40, 60, 10, 70, 20, 50, 20, 30, 40}
};
for( int i = 0; i < 3; ++i )
{
auto y = yValues.at( i );
QVector<QPointF> dataPoints;
dataPoints.reserve( number );
qreal t0 = y[0];
qreal step = 10;
boost::math::cubic_b_spline<qreal> spline1( yValues1.data(), yValues1.size(), t0, step );
boost::math::cubic_b_spline<qreal> spline( y.data(), y.size(), t0, step );
for( int x = 0; x < number; ++x )
{
qreal y = spline1( x );
dataPoints1.append( QPointF( x, y ) );
const qreal y = spline( x );
dataPoints.append( QPointF( x, y ) );
}
m_diagram->addDataPoints( dataPoints, Diagram::Area );
}
m_diagram->setDataPoints( dataPoints1 );
m_diagram->setYMax( 100 );
addItem( m_diagram );
@ -113,4 +123,11 @@ UsageDiagram::UsageDiagram( QQuickItem* parent )
m_captionBox->addItem( new CaptionItem( CaptionItem::Gas, this ) );
}
void UsageDiagram::updateLayout()
{
auto weekdaysHeight = m_weekdays->preferredSize().height();
m_diagram->setHeight( m_diagram->height() - weekdaysHeight );
m_captionBox->setPosition( {0, 0} );
}
#include "Diagram.moc"

View File

@ -130,6 +130,8 @@ class UsageDiagram : public Box
UsageDiagram( QQuickItem* parent );
void updateLayout() override;
QskAspect::Subcontrol effectiveSubcontrol(
QskAspect::Subcontrol subControl ) const override final
{

View File

@ -11,7 +11,7 @@ IdlChartSegmentsNode::IdlChartSegmentsNode()
setMaterial( &m_material );
}
void IdlChartSegmentsNode::update( const QRectF& rect, const QColor& color, const QVector<QPointF>& dataPoints, int xGridLines )
void IdlChartSegmentsNode::update( const QRectF& rect, const QColor& color, const QVector<QVector<QPointF> >& dataPoints, int xGridLines )
{
Q_UNUSED( rect );

View File

@ -9,7 +9,7 @@ class IdlChartSegmentsNode : public QSGGeometryNode
public:
IdlChartSegmentsNode();
void update( const QRectF& rect, const QColor& color, const QVector<QPointF>& dataPoints, int xGridLines );
void update( const QRectF& rect, const QColor& color, const QVector< QVector<QPointF> >& dataPoints, int xGridLines );
private:
QSGFlatColorMaterial m_material;
@ -17,6 +17,6 @@ class IdlChartSegmentsNode : public QSGGeometryNode
QRectF m_rect;
QColor m_color;
QVector<QPointF> m_dataPoints;
QVector< QVector<QPointF> > m_dataPoints;
int m_xGridLines;
};