File indexing completed on 2024-05-12 04:20:15
0001 /** 0002 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. 0003 * 0004 * This file is part of the KD Chart library. 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "mainwindow.h" 0010 #include "framewidget.h" 0011 0012 #include <KChartChart> 0013 #include <KChartAbstractCoordinatePlane> 0014 #include <KChartLineDiagram> 0015 #include <KChartLineAttributes> 0016 #include <KChartTextAttributes> 0017 #include <KChartDataValueAttributes> 0018 #include <KChartThreeDLineAttributes> 0019 #include <KChartMarkerAttributes> 0020 #include <KChartFrameAttributes> 0021 #include <KChartBackgroundAttributes> 0022 #include <KChartLegend> 0023 0024 #include <QDebug> 0025 #include <QPainter> 0026 #include <QTime> 0027 #include <QElapsedTimer> 0028 0029 using namespace KChart; 0030 0031 static QPixmap drawIntoPixmap( const QSize& size, KChart::Chart* chart ) 0032 { 0033 QPixmap pix( size ); 0034 pix.fill( Qt::white ); 0035 QPainter painter( &pix ); 0036 chart->paint( &painter, QRect( 0, 0, size.width(), size.height() ) ); 0037 return pix; 0038 } 0039 0040 // When set, this example uses FrameWidget which uses Chart::paint to paint itself. 0041 // When not set, this example uses a Chart widget directly. 0042 #define USE_FRAME_WIDGET 1 0043 0044 0045 MainWindow::MainWindow( QWidget* parent ) : 0046 QWidget( parent ) 0047 { 0048 0049 setupUi( this ); 0050 0051 connect( lineTypeCB, SIGNAL(currentIndexChanged(QString)), this, SLOT(setLineType(QString)) ); 0052 connect( paintLegendCB, SIGNAL(toggled(bool)), this, SLOT(setLegendVisible(bool)) ); 0053 connect( paintValuesCB, SIGNAL(toggled(bool)), this, SLOT(setValuesVisible(bool)) ); 0054 connect( paintMarkersCB, SIGNAL(toggled(bool)), this, SLOT(setMarkersVisible(bool)) ); 0055 connect( markersStyleCB, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMarkers()) ); 0056 connect( markersWidthSB, SIGNAL(valueChanged(int)), this, SLOT(updateMarkersHeight()) ); 0057 connect( markersHeightSB, SIGNAL(valueChanged(int)), this, SLOT(updateMarkersWidth()) ); 0058 connect( displayAreasCB, SIGNAL(toggled(bool)), this, SLOT(updateAreas(bool)) ); 0059 connect( transparencySB, SIGNAL(valueChanged(int)), this, SLOT(updateAreasTransparency()) ); 0060 connect( zoomFactorSB, SIGNAL(valueChanged(double)), this, SLOT(setZoomFactor(qreal)) ); 0061 connect( hSBar, SIGNAL(valueChanged(int)), this, SLOT(setHPos(int)) ); 0062 connect( vSBar, SIGNAL(valueChanged(int)), this, SLOT(setVPos(int)) ); 0063 connect( savePB, SIGNAL(clicked()), this, SLOT(saveChart()) ); 0064 0065 QHBoxLayout* chartLayout = new QHBoxLayout( chartFrame ); 0066 #ifdef USE_FRAME_WIDGET 0067 FrameWidget* chartFrameWidget = new FrameWidget(); 0068 chartLayout->addWidget( chartFrameWidget ); 0069 #endif 0070 hSBar->setVisible( false ); 0071 vSBar->setVisible( false ); 0072 0073 m_model.loadFromCSV( ":/empty" ); 0074 0075 // Set up the diagram 0076 m_lines = new LineDiagram(); 0077 0078 m_lines->setModel( &m_model ); 0079 0080 CartesianAxis *xAxis = new CartesianAxis( m_lines ); 0081 CartesianAxis *yAxis = new CartesianAxis ( m_lines ); 0082 CartesianAxis *axisTop = new CartesianAxis ( m_lines ); 0083 CartesianAxis *axisRight = new CartesianAxis ( m_lines ); 0084 xAxis->setPosition ( KChart::CartesianAxis::Bottom ); 0085 yAxis->setPosition ( KChart::CartesianAxis::Left ); 0086 axisTop->setPosition( KChart::CartesianAxis::Top ); 0087 axisRight->setPosition( KChart::CartesianAxis::Right ); 0088 0089 m_lines->addAxis( xAxis ); 0090 m_lines->addAxis( yAxis ); 0091 m_lines->addAxis( axisTop ); 0092 m_lines->addAxis( axisRight ); 0093 0094 m_chart = new Chart(); 0095 //m_chart->setGlobalLeading(10,10,10,10); // by default there is no leading 0096 0097 #ifdef USE_FRAME_WIDGET 0098 chartFrameWidget->setChart( m_chart ); 0099 // make sure, we re-draw after changing one of the chart's properties 0100 connect( m_chart, SIGNAL(propertiesChanged()), 0101 chartFrameWidget, SLOT(update()) ) ; 0102 #else 0103 chartLayout->addWidget( m_chart ); 0104 #endif 0105 0106 m_chart->coordinatePlane()->replaceDiagram( m_lines ); 0107 0108 for ( int iColumn = 0; iColumn<m_lines->model()->columnCount(); ++iColumn ) { 0109 QPen pen(m_lines->pen( iColumn )); 0110 pen.setWidth(4); 0111 m_lines->setPen( iColumn, pen ); 0112 } 0113 0114 FrameAttributes faChart( m_chart->frameAttributes() ); 0115 faChart.setVisible( true ); 0116 faChart.setPen( QPen(QColor(0x60,0x60,0xb0), 8) ); 0117 m_chart->setFrameAttributes( faChart ); 0118 0119 BackgroundAttributes baChart( m_chart->backgroundAttributes() ); 0120 baChart.setVisible( true ); 0121 baChart.setBrush( QColor(0xd0,0xd0,0xff) ); 0122 m_chart->setBackgroundAttributes( baChart ); 0123 0124 // Set up the legend 0125 m_legend = new Legend( m_lines, m_chart ); 0126 0127 m_legend->setPosition( Position::South ); 0128 m_legend->setAlignment( Qt::AlignRight ); 0129 m_legend->setShowLines( false ); 0130 m_legend->setTitleText( QStringLiteral( "Legend" ) ); 0131 m_legend->setOrientation( Qt::Horizontal ); 0132 0133 // setting the legend frame and background to the same color: 0134 const QColor legendColor(0xff,0xe0,0x80); 0135 FrameAttributes faLegend( m_legend->frameAttributes() ); 0136 faLegend.setVisible( true ); 0137 faLegend.setPen( QPen(legendColor, 1) ); 0138 m_legend->setFrameAttributes( faLegend ); 0139 0140 BackgroundAttributes baLegend( m_legend->backgroundAttributes() ); 0141 baLegend.setVisible( true ); 0142 baLegend.setBrush( legendColor ); 0143 m_legend->setBackgroundAttributes( baLegend ); 0144 0145 m_chart->addLegend( m_legend ); 0146 0147 // for illustration we paint the same chart at different sizes: 0148 QSize size1 = QSize( 200, 200 ); 0149 QSize size2 = QSize( 800, 800 ); 0150 m_pix1 = drawIntoPixmap( size1, m_chart ); 0151 m_pix2 = drawIntoPixmap( size2, m_chart ); 0152 m_pix2 = m_pix2.scaled( size1 ); 0153 0154 m_smallChart1 = new QLabel( this ); 0155 m_smallChart1->setWindowTitle( "200x200" ); 0156 m_smallChart1->setPixmap( m_pix1 ); 0157 m_smallChart1->setFixedSize( m_pix1.size() ); 0158 m_smallChart1->move( width() - m_pix1.width()*2, 0159 height()/2 - m_pix1.height()-5 ); 0160 m_smallChart1->show(); 0161 0162 m_smallChart2 = new QLabel( this ); 0163 m_smallChart2->setWindowTitle( "800x800 scaled down" ); 0164 m_smallChart2->setPixmap( m_pix2 ); 0165 m_smallChart2->setFixedSize( m_pix2.size() ); 0166 m_smallChart2->move( width() - m_pix2.width()*2, 0167 height()/2 + 5 ); 0168 m_smallChart2->show(); 0169 0170 faChart.setPen( QPen(QColor(0xb0,0xb0,0xff), 8) ); 0171 m_chart->setFrameAttributes( faChart ); 0172 0173 // initialize attributes; this is necessary because we need to enable data value attributes before 0174 // any of them (e.g. only markers) can be displayed. but if we enable data value attributes, a default 0175 // data value text is included, even if we only wanted to set markers. so we enable DVA and then 0176 // individually disable the parts we don't want. 0177 setValuesVisible( false ); 0178 setMarkersVisible( false ); 0179 } 0180 0181 void MainWindow::updateData(QString data) 0182 { 0183 QElapsedTimer t; 0184 t.start(); 0185 0186 m_model.loadFromCSV( data ); 0187 0188 qDebug("Time for loading data %s: %lld ms", data.toLatin1().constData(), t.elapsed()); 0189 t.restart(); 0190 0191 QSize size1 = QSize( 200, 200 ); 0192 QSize size2 = QSize( 800, 800 ); 0193 m_pix1 = drawIntoPixmap( size1, m_chart ); 0194 m_pix2 = drawIntoPixmap( size2, m_chart ); 0195 0196 qDebug("Time for drawing pixmap %s: %lld ms", data.toLatin1().constData(), t.elapsed()); 0197 t.restart(); 0198 0199 m_lines->setModel( &m_model ); 0200 0201 qDebug("Time for setting model %s: %lld ms", data.toLatin1().constData(), t.elapsed()); 0202 t.restart(); 0203 0204 m_smallChart1->setPixmap( m_pix1 ); 0205 m_smallChart2->setPixmap( m_pix2 ); 0206 0207 m_smallChart1->show(); 0208 m_smallChart2->show(); 0209 0210 qDebug("Time for setting pixmap %s: %lld ms", data.toLatin1().constData(), t.elapsed()); 0211 t.restart(); 0212 0213 } 0214 0215 void MainWindow::setLineType( const QString & text ) 0216 { 0217 if ( text == "Normal" ) 0218 m_lines->setType( LineDiagram::Normal ); 0219 else if ( text == "Stacked" ) 0220 m_lines->setType( LineDiagram::Stacked ); 0221 else if ( text == "Percent" ) 0222 m_lines->setType( LineDiagram::Percent ); 0223 else 0224 qWarning (" Does not match any type"); 0225 } 0226 0227 void MainWindow::setLegendVisible(bool visible ) 0228 { 0229 KChart::Legend* legend = m_chart->legend(); 0230 if ( visible != ( legend != nullptr ) ) { 0231 if ( visible ) 0232 m_chart->addLegend( m_legend ); 0233 else 0234 m_chart->takeLegend( legend ); 0235 } 0236 } 0237 0238 void MainWindow::setValuesVisible(bool visible ) 0239 { 0240 const int colCount = m_lines->model()->columnCount(); 0241 for ( int iColumn = 0; iColumn<colCount; ++iColumn ) { 0242 DataValueAttributes a = m_lines->dataValueAttributes( iColumn ); 0243 a.setVisible( true ); 0244 0245 TextAttributes ta = a.textAttributes(); 0246 ta.setRotation( 0 ); 0247 ta.setFont( QFont( "Comic", 10 ) ); 0248 ta.setPen( m_lines->brush( iColumn ).color() ); 0249 ta.setVisible( visible ); 0250 0251 a.setTextAttributes( ta ); 0252 m_lines->setDataValueAttributes( iColumn, a); 0253 } 0254 } 0255 0256 0257 void MainWindow::setMarkersVisible( bool visible ) 0258 { 0259 paintMarkers( visible, QSize() ); 0260 } 0261 0262 void MainWindow::updateMarkers() 0263 { 0264 setMarkersVisible( paintMarkersCB->isChecked() ); 0265 } 0266 0267 void MainWindow::updateMarkersHeight() 0268 { 0269 markersHeightSB->setValue( markersWidthSB->value() ); 0270 updateMarkers(); 0271 } 0272 0273 void MainWindow::updateMarkersWidth() 0274 { 0275 markersWidthSB->setValue( markersHeightSB->value() ); 0276 updateMarkers(); 0277 } 0278 0279 void MainWindow::updateAreas( bool visible ) 0280 { 0281 const int colCount = m_lines->model()->columnCount(); 0282 for ( int iColumn = 0; iColumn<colCount; ++iColumn ) { 0283 LineAttributes la( m_lines->lineAttributes( iColumn ) ); 0284 la.setDisplayArea( visible ); 0285 if ( visible ) 0286 la.setTransparency( transparencySB->value() ); 0287 m_lines->setLineAttributes( iColumn, la ); 0288 } 0289 } 0290 0291 void MainWindow::updateAreasTransparency() 0292 { 0293 if ( !displayAreasCB->isChecked() ) 0294 displayAreasCB->setChecked( true ); 0295 else 0296 updateAreas( true ); 0297 } 0298 0299 void MainWindow::setZoomFactor( qreal factor ) 0300 { 0301 const bool isZoomedIn = factor > 1.0f; 0302 hSBar->setVisible( isZoomedIn ); 0303 vSBar->setVisible( isZoomedIn ); 0304 if ( !isZoomedIn ) { 0305 hSBar->setValue( 500 ); 0306 vSBar->setValue( 500 ); 0307 } 0308 m_chart->coordinatePlane()->setZoomFactorX( factor ); 0309 m_chart->coordinatePlane()->setZoomFactorY( factor ); 0310 } 0311 0312 void MainWindow::setHPos( int hPos ) 0313 { 0314 m_chart->coordinatePlane()->setZoomCenter( QPointF(hPos/1000.0, vSBar->value()/1000.0) ); 0315 m_chart->update(); 0316 } 0317 0318 void MainWindow::setVPos( int vPos ) 0319 { 0320 m_chart->coordinatePlane()->setZoomCenter( QPointF( hSBar->value()/1000.0, vPos/1000.0) ); 0321 } 0322 0323 // since DataValue markers have no relative sizing mode we need to scale them for printing 0324 void MainWindow::paintMarkers( bool checked, const QSize& printSize ) 0325 { 0326 MarkerAttributes::MarkerStylesMap map; 0327 map.insert( 0, MarkerAttributes::MarkerSquare ); 0328 map.insert( 1, MarkerAttributes::MarkerCircle ); 0329 map.insert( 2, MarkerAttributes::MarkerRing ); 0330 map.insert( 3, MarkerAttributes::MarkerCross ); 0331 map.insert( 4, MarkerAttributes::MarkerDiamond ); 0332 0333 // next: Specify column- / cell-specific attributes! 0334 const int colCount = m_lines->model()->columnCount(); 0335 for ( int iColumn = 0; iColumn<colCount; ++iColumn ) { 0336 DataValueAttributes dva = m_lines->dataValueAttributes( iColumn ); 0337 dva.setVisible( true ); 0338 MarkerAttributes ma( dva.markerAttributes() ); 0339 0340 switch ( markersStyleCB->currentIndex() ) { 0341 case 0: 0342 ma.setMarkerStyle( MarkerAttributes::MarkerSquare ); 0343 break; 0344 case 1: 0345 // Column-specific attributes 0346 ma.setMarkerStyle( map.value( iColumn ) ); 0347 break; 0348 case 2: 0349 ma.setMarkerStyle( MarkerAttributes::MarkerCircle ); 0350 break; 0351 case 3: 0352 ma.setMarkerStyle( MarkerAttributes::MarkerDiamond ); 0353 break; 0354 case 4: 0355 ma.setMarkerStyle( MarkerAttributes::Marker1Pixel ); 0356 break; 0357 case 5: 0358 ma.setMarkerStyle( MarkerAttributes::Marker4Pixels ); 0359 break; 0360 case 6: 0361 ma.setMarkerStyle( MarkerAttributes::MarkerRing ); 0362 break; 0363 case 7: 0364 ma.setMarkerStyle( MarkerAttributes::MarkerCross ); 0365 break; 0366 case 8: 0367 ma.setMarkerStyle( MarkerAttributes::MarkerFastCross ); 0368 break; 0369 default: 0370 Q_ASSERT( false ); 0371 } 0372 ma.setVisible( checked ); 0373 0374 qreal factorWidth = printSize.isValid() ? ( printSize.width() / m_chart->rect().width() ) : 1.0f; 0375 qreal factorHeight = printSize.isValid() ? ( printSize.height() / m_chart->rect().height() ) : 1.0f; 0376 ma.setMarkerSize( QSize( markersWidthSB->value() * factorWidth, markersHeightSB->value() * factorHeight ) ); 0377 0378 dva.setMarkerAttributes( ma ); 0379 m_lines->setDataValueAttributes( iColumn, dva ); 0380 0381 // make a special one for certain values 0382 DataValueAttributes yellowAttributes( dva ); 0383 MarkerAttributes yellowMarker( yellowAttributes.markerAttributes() ); 0384 yellowMarker.setMarkerColor( Qt::yellow ); 0385 yellowAttributes.setMarkerAttributes( yellowMarker ); 0386 0387 const int rowCount = m_lines->model()->rowCount(); 0388 for ( int j=0; j< rowCount; ++j ) { 0389 QModelIndex index = m_lines->model()->index( j, iColumn, QModelIndex() ); 0390 QBrush brush = m_lines->model()->headerData( iColumn, Qt::Vertical, DatasetBrushRole ).value<QBrush>(); 0391 qreal value = m_lines->model()->data( index ).toReal(); 0392 /* Set a specific color - marker for a specific value */ 0393 if ( value == 13 ) { 0394 m_lines->setDataValueAttributes( index, yellowAttributes ); 0395 } 0396 } 0397 } 0398 } 0399 0400 void MainWindow::saveChart() 0401 { 0402 qDebug() << "Painting into PNG"; 0403 QPixmap qpix(600,600); 0404 QPainter painter(&qpix); 0405 painter.setBrush(Qt::white); 0406 painter.fillRect( 0, 0, 600, 600, Qt::white); 0407 m_chart->paint( &painter, 0408 QRect(100, 100, 400, 400) ); 0409 painter.end(); 0410 qpix.save("kchart-demo.png", "PNG"); 0411 qDebug() << "Painting into PNG - done"; 0412 } 0413 0414 void MainWindow::resizeEvent ( QResizeEvent * ) 0415 { 0416 m_smallChart1->move( width() - m_pix1.width()*2, 0417 height()/2 - m_pix1.height()-5 ); 0418 m_smallChart2->move( width() - m_pix2.width()*2, 0419 height()/2 + 5 ); 0420 } 0421 0422