123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- #include "chartline.h"
- #include <QPen>
- #include <QBrush>
- #include <QFont>
- #include <QPixmap>
- #include <QDebug>
- #include <algorithm>
- ChartLine::ChartLine(QWidget *parent)
- : QChartView(parent),
- m_chart(new QChart()),
- m_axisX(new QValueAxis()),
- m_axisY(new QValueAxis()),
- m_lineSeries(new QLineSeries())
- {
- // 设置背景透明
- setAttribute(Qt::WA_TranslucentBackground);
- setStyleSheet("background: transparent;");
- m_chart->setBackgroundBrush(Qt::transparent);
- // 添加坐标轴
- m_chart->addAxis(m_axisX, Qt::AlignBottom);
- m_chart->addAxis(m_axisY, Qt::AlignLeft);
- // 设置初始坐标轴范围及样式
- // 坐标轴
- m_axisX->setRange(0, 40);
- m_axisX->setTickCount(9);
- m_axisX->setLabelFormat("%.0f");
- m_axisX->setTitleFont(QFont("思源黑体", 10));
- m_axisX->setTitleBrush(QBrush(QColor("#1D2087")));
- m_axisY->setRange(-60, 120);
- m_axisY->setTickCount(7);
- m_axisY->setLabelFormat("%.0f");
- m_axisY->setTitleFont(QFont("思源黑体", 10));
- m_axisY->setTitleBrush(QBrush(QColor("#1D2087")));
- // 图表标题 + 隐藏图例
- m_chart->setTitleFont(QFont("思源黑体", 10));
- m_chart->setTitleBrush(QBrush(QColor("#1D2087")));
- m_chart->legend()->hide();
- // 设置折线样式 (QLineSeries)
- QPen linePen(QColor("#4AB832"));
- linePen.setWidth(1);
- m_lineSeries->setPen(linePen);
- m_lineSeries->setName("Combined Line");
- m_chart->addSeries(m_lineSeries);
- m_lineSeries->attachAxis(m_axisX);
- m_lineSeries->attachAxis(m_axisY);
- // 隐藏图例
- m_chart->legend()->hide();
- // 6. 设置网格线样式虚线
- QPen gridPen(QColor("#29517E"));
- gridPen.setWidth(1);
- gridPen.setStyle(Qt::DashLine);
- m_axisY->setGridLinePen(gridPen);
- m_axisX->setGridLineVisible(false);
- QFont axisFont("思源黑体", 6); // 第二个参数是字号,数值越小,文字越小
- m_axisX->setLabelsFont(axisFont);
- m_axisY->setLabelsFont(axisFont);
- // 设置图表到 ChartView
- setChart(m_chart);
- // PlotArea 边框
- m_chart->setPlotAreaBackgroundPen(QPen(QColor("#29517E"), 1, Qt::SolidLine));
- m_chart->setPlotAreaBackgroundVisible(true);
- // 启用抗锯齿
- setRenderHint(QPainter::Antialiasing);
- }
- void ChartLine::setChartLabels(const QString &chartTitle,
- const QString &xAxisLabel,
- const QString &yAxisLabel)
- {
- // 设置图表标题
- m_chart->setTitle(chartTitle);
- // 设置 X 轴和 Y 轴标题
- m_axisX->setTitleText(xAxisLabel);
- m_axisY->setTitleText(yAxisLabel);
- }
- void ChartLine::addDataSeries(const DataSeries &series)
- {
- if (m_dataSeriesMap.contains(series.seriesName)) {
- qDebug() << "Series already exists:" << series.seriesName;
- return;
- }
- // 存储系列信息
- m_dataSeriesMap.insert(series.seriesName, series);
- // 创建对应的 QScatterSeries
- QScatterSeries* scatter = new QScatterSeries();
- scatter->setName(series.seriesName + "_scatter");
- // 隐藏 scatter series markers
- scatter->setMarkerSize(0.0);
- scatter->setPen(Qt::NoPen);
- scatter->setBrush(Qt::NoBrush);
- // 添加到图表并绑定坐标轴
- m_chart->addSeries(scatter);
- scatter->attachAxis(m_axisX);
- scatter->attachAxis(m_axisY);
- // 存储 scatter 系列
- m_scatterSeriesMap.insert(series.seriesName, scatter);
- // 更新散点数据
- scatter->replace(series.data);
- // 创建自定义图标
- QList<QGraphicsPixmapItem*> pixmapList;
- for (const QPointF &point : series.data) {
- QPointF position = m_chart->mapToPosition(point, m_lineSeries);
- QGraphicsPixmapItem *pixmapItem = new QGraphicsPixmapItem(series.markerIcon);
- pixmapItem->setPos(position - QPointF(series.markerIcon.width() / 2, series.markerIcon.height() / 2));
- pixmapItem->setParentItem(m_chart);
- pixmapList.append(pixmapItem);
- }
- m_pixmapItemsMap.insert(series.seriesName, pixmapList);
- // 重新构建折线数据
- rebuildLineSeries();
- }
- void ChartLine::removeDataSeries(const QString &seriesName)
- {
- if (!m_dataSeriesMap.contains(seriesName)) {
- qDebug() << "Series does not exist:" << seriesName;
- return;
- }
- // 移除系列信息
- m_dataSeriesMap.remove(seriesName);
- // 移除对应的 scatter 系列
- if (m_scatterSeriesMap.contains(seriesName)) {
- QScatterSeries* scatter = m_scatterSeriesMap.value(seriesName);
- m_chart->removeSeries(scatter);
- delete scatter;
- m_scatterSeriesMap.remove(seriesName);
- }
- // 移除并删除自定义图标
- if (m_pixmapItemsMap.contains(seriesName)) {
- for (QGraphicsPixmapItem* pixmap : m_pixmapItemsMap[seriesName]) {
- m_chart->scene()->removeItem(pixmap);
- delete pixmap;
- }
- m_pixmapItemsMap.remove(seriesName);
- }
- // 重新构建折线数据
- rebuildLineSeries();
- }
- void ChartLine::updateDataSeries(const QString &seriesName, const QList<QPointF> &data)
- {
- if (!m_dataSeriesMap.contains(seriesName)) {
- qDebug() << "Series does not exist:" << seriesName;
- return;
- }
- // 更新数据
- m_dataSeriesMap[seriesName].data = data;
- // 更新对应的 scatter 系列
- if (m_scatterSeriesMap.contains(seriesName)) {
- QScatterSeries* scatter = m_scatterSeriesMap.value(seriesName);
- scatter->replace(data);
- }
- // 更新自定义图标位置
- if (m_pixmapItemsMap.contains(seriesName)) {
- const QList<QGraphicsPixmapItem*> &pixmaps = m_pixmapItemsMap[seriesName];
- QList<QPointF> &seriesData = m_dataSeriesMap[seriesName].data;
- int minSize = qMin(pixmaps.size(), seriesData.size());
- for (int i = 0; i < minSize; ++i) {
- QPointF position = m_chart->mapToPosition(seriesData[i], m_lineSeries);
- pixmaps[i]->setPos(position - QPointF(pixmaps[i]->pixmap().width() / 2, pixmaps[i]->pixmap().height() / 2));
- }
- // 移除多余的 pixmap
- if (pixmaps.size() > seriesData.size()) {
- for (int i = seriesData.size(); i < pixmaps.size(); ++i) {
- m_chart->scene()->removeItem(pixmaps[i]);
- delete pixmaps[i];
- }
- QList<QGraphicsPixmapItem*> updatedList;
- for (int i = 0; i < seriesData.size(); ++i) {
- updatedList.append(pixmaps[i]);
- }
- m_pixmapItemsMap[seriesName] = updatedList;
- }
- // 添加缺失的 pixmap
- else if (pixmaps.size() < seriesData.size()) {
- for (int i = pixmaps.size(); i < seriesData.size(); ++i) {
- QPointF position = m_chart->mapToPosition(seriesData[i], m_lineSeries);
- QGraphicsPixmapItem *pixmapItem = new QGraphicsPixmapItem(m_dataSeriesMap[seriesName].markerIcon);
- pixmapItem->setPos(position - QPointF(m_dataSeriesMap[seriesName].markerIcon.width() / 2, m_dataSeriesMap[seriesName].markerIcon.height() / 2));
- pixmapItem->setParentItem(m_chart);
- m_pixmapItemsMap[seriesName].append(pixmapItem);
- }
- }
- }
- // 重新构建折线数据
- rebuildLineSeries();
- }
- void ChartLine::rebuildLineSeries()
- {
- // 清空当前折线数据
- m_lineSeries->clear();
- // 汇总所有数据点
- QList<QPointF> allPoints;
- for (const auto &series : m_dataSeriesMap) {
- allPoints.append(series.data);
- }
- // 排序数据点以确保折线正确
- std::sort(allPoints.begin(), allPoints.end(), [](const QPointF &a, const QPointF &b) {
- return a.x() < b.x();
- });
- // 添加到折线系列
- m_lineSeries->replace(allPoints);
- // 更新自定义图标位置
- updateMarkers();
- }
- void ChartLine::updateMarkers()
- {
- for (auto it = m_pixmapItemsMap.begin(); it != m_pixmapItemsMap.end(); ++it) {
- const QString &seriesName = it.key();
- const QList<QPointF> &data = m_dataSeriesMap[seriesName].data;
- const QList<QGraphicsPixmapItem*> &pixmaps = it.value();
- for (int i = 0; i < data.size() && i < pixmaps.size(); ++i) {
- QPointF position = m_chart->mapToPosition(data[i], m_lineSeries);
- pixmaps[i]->setPos(position - QPointF(pixmaps[i]->pixmap().width() / 2, pixmaps[i]->pixmap().height() / 2));
- }
- }
- }
- void ChartLine::resizeEvent(QResizeEvent *event)
- {
- QChartView::resizeEvent(event);
- updateMarkers();
- }
|