#include "chartgraph.h" #include #include #include #include #include #include #include #include #include #include #include class ChartView : public QChartView { QPointF _mousePos; bool _scroll = false; public: ChartView(QWidget *parent) : QChartView(parent) { } protected: void keyPressEvent(QKeyEvent *event) override { switch(event->key()) { case Qt::Key_Plus: chart()->zoomIn(); break; case Qt::Key_Minus: chart()->zoomOut(); break; case Qt::Key_Left: chart()->scroll(-10, 0); break; case Qt::Key_Right: chart()->scroll(10, 0); break; case Qt::Key_Up: chart()->scroll(0, 10); break; case Qt::Key_Down: chart()->scroll(0, -10); break; default: QGraphicsView::keyPressEvent(event); break; } } void mousePressEvent(QMouseEvent *event) override { if(event->button() == Qt::LeftButton) { _scroll = true; _mousePos = event->position(); } QChartView::mousePressEvent(event); } void mouseMoveEvent(QMouseEvent *event) override { if(_scroll) { QPointF pos = event->position(); chart()->scroll(_mousePos.x() - pos.x(), pos.y() - _mousePos.y()); _mousePos = pos; } QChartView::mouseMoveEvent(event); } void mouseReleaseEvent(QMouseEvent *event) override { _scroll = false; QChartView::mouseReleaseEvent(event); } }; ChartGraph::ChartGraph(QWidget *parent) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setModal(false); _chartView = new ChartView(this); setLayout(new QVBoxLayout); layout()->addWidget(_chartView); _chart = new QChart; _chartView->setChart(_chart); _chartView->setRenderHint(QPainter::Antialiasing); resize(1024, 768); QMenuBar *menuBar = new QMenuBar(this); menuBar->addAction(tr("Save"), this, &ChartGraph::save); layout()->setMenuBar(menuBar); } void ChartGraph::plot(const QVariant &graph) { QVariantMap map = graph.toMap(); _chart->setTitle(map["title"].toString()); if(map.contains("legend")) { QVariantMap legend = map["legend"].toMap(); if(legend.contains("visible")) _chart->legend()->setVisible(legend["visible"].toBool()); QString align = legend["align"].toString(); if(align == "top") _chart->legend()->setAlignment(Qt::AlignTop); else if(align == "left") _chart->legend()->setAlignment(Qt::AlignLeft); else if(align == "bottom") _chart->legend()->setAlignment(Qt::AlignBottom); else if(align == "right") _chart->legend()->setAlignment(Qt::AlignRight); } QBarSeries *barSeries = nullptr; qreal minY = INFINITY; qreal maxY = -INFINITY; for(auto s : map["series"].toList()) { QVariantMap serie = s.toMap(); QString type = serie["type"].toString(); if(type == "line" || type == "points" || type == "linePoints" || type.isEmpty()) { QXYSeries *series = nullptr; if(type == "points") { QScatterSeries *scatter = new QScatterSeries(_chart); series = scatter; QString shape = serie["shape"].toString(); if(shape == "circle")scatter->setMarkerShape(QScatterSeries::MarkerShapeCircle); else if(shape == "rectangle")scatter->setMarkerShape(QScatterSeries::MarkerShapeRectangle); else if(shape == "triangle")scatter->setMarkerShape(QScatterSeries::MarkerShapeTriangle); else if(shape == "star")scatter->setMarkerShape(QScatterSeries::MarkerShapeStar); else if(shape == "pentagon")scatter->setMarkerShape(QScatterSeries::MarkerShapePentagon); } else { series = new QLineSeries(_chart); } series->setName(serie["title"].toString()); QVariantList x = serie["x"].toList(); QVariantList y = serie["y"].toList(); if(x.isEmpty()) { for(int i = 0; i < y.size(); i++) { qreal val = y[i].toDouble(); minY = std::min(minY, val); maxY = std::max(maxY, val); series->append(i, val); } } else { int size = std::min(x.size(), y.size()); for(int i = 0; i < size; i++) { qreal val = y[i].toDouble(); minY = std::min(minY, val); maxY = std::max(maxY, val); series->append(x[i].toDouble(), val); } } _chart->addSeries(series); if(serie["bestFit"].toBool()) { series->setBestFitLineVisible(true); QPen pen = series->bestFitLinePen(); pen.setColor(series->color()); pen.setStyle(Qt::DashLine); series->setBestFitLinePen(pen); } if(type == "linePoints") series->setPointsVisible(true); if(serie.contains("color")) { QString color = serie["color"].toString(); if(QColor::isValidColorName(color))series->setColor(QColor::fromString(color)); } } else if(type == "bar") { if(!barSeries) { barSeries = new QBarSeries(_chart); _chart->addSeries(barSeries); } QBarSet *set = new QBarSet(serie["title"].toString()); QVariantList y = serie["y"].toList(); for(int i = 0; i < y.size(); i++) { qreal val = y[i].toDouble(); minY = std::min(minY, val); maxY = std::max(maxY, val); set->append(val); } barSeries->append(set); if(serie.contains("color")) { QString color = serie["color"].toString(); if(QColor::isValidColorName(color))set->setColor(QColor::fromString(color)); } } } _chart->createDefaultAxes(); QValueAxis *yaxis = qobject_cast(_chart->axes(Qt::Vertical).front()); if(yaxis) { qreal off = (maxY - minY) * 0.05; yaxis->setRange(std::min(minY - off, 0.0), maxY + off); } show(); } void ChartGraph::save() { QSettings settings; QString dir = settings.value("mainwindow/lastdir").toString(); QString output = QFileDialog::getSaveFileName(this, tr("Save as"), dir, "PNG (*.png)"); if(!output.isEmpty()) { QPixmap graph = _chartView->grab(); graph.toImage().save(output); } }