chartline.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #include "chartline.h"
  2. #include <QPen>
  3. #include <QBrush>
  4. #include <QFont>
  5. #include <QPixmap>
  6. #include <QDebug>
  7. #include <algorithm>
  8. ChartLine::ChartLine(QWidget *parent)
  9. : QChartView(parent),
  10. m_chart(new QChart()),
  11. m_axisX(new QValueAxis()),
  12. m_axisY(new QValueAxis()),
  13. m_lineSeries(new QLineSeries())
  14. {
  15. // 设置背景透明
  16. setAttribute(Qt::WA_TranslucentBackground);
  17. setStyleSheet("background: transparent;");
  18. m_chart->setBackgroundBrush(Qt::transparent);
  19. // 添加坐标轴
  20. m_chart->addAxis(m_axisX, Qt::AlignBottom);
  21. m_chart->addAxis(m_axisY, Qt::AlignLeft);
  22. // 设置初始坐标轴范围及样式
  23. // 坐标轴
  24. m_axisX->setRange(0, 40);
  25. m_axisX->setTickCount(9);
  26. m_axisX->setLabelFormat("%.0f");
  27. m_axisX->setTitleFont(QFont("思源黑体", 10));
  28. m_axisX->setTitleBrush(QBrush(QColor("#1D2087")));
  29. m_axisY->setRange(-60, 120);
  30. m_axisY->setTickCount(7);
  31. m_axisY->setLabelFormat("%.0f");
  32. m_axisY->setTitleFont(QFont("思源黑体", 10));
  33. m_axisY->setTitleBrush(QBrush(QColor("#1D2087")));
  34. // 图表标题 + 隐藏图例
  35. m_chart->setTitleFont(QFont("思源黑体", 10));
  36. m_chart->setTitleBrush(QBrush(QColor("#1D2087")));
  37. m_chart->legend()->hide();
  38. // 设置折线样式 (QLineSeries)
  39. QPen linePen(QColor("#4AB832"));
  40. linePen.setWidth(1);
  41. m_lineSeries->setPen(linePen);
  42. m_lineSeries->setName("Combined Line");
  43. m_chart->addSeries(m_lineSeries);
  44. m_lineSeries->attachAxis(m_axisX);
  45. m_lineSeries->attachAxis(m_axisY);
  46. // 隐藏图例
  47. m_chart->legend()->hide();
  48. // 6. 设置网格线样式虚线
  49. QPen gridPen(QColor("#29517E"));
  50. gridPen.setWidth(1);
  51. gridPen.setStyle(Qt::DashLine);
  52. m_axisY->setGridLinePen(gridPen);
  53. m_axisX->setGridLineVisible(false);
  54. QFont axisFont("思源黑体", 6); // 第二个参数是字号,数值越小,文字越小
  55. m_axisX->setLabelsFont(axisFont);
  56. m_axisY->setLabelsFont(axisFont);
  57. // 设置图表到 ChartView
  58. setChart(m_chart);
  59. // PlotArea 边框
  60. m_chart->setPlotAreaBackgroundPen(QPen(QColor("#29517E"), 1, Qt::SolidLine));
  61. m_chart->setPlotAreaBackgroundVisible(true);
  62. // 启用抗锯齿
  63. setRenderHint(QPainter::Antialiasing);
  64. }
  65. void ChartLine::setChartLabels(const QString &chartTitle,
  66. const QString &xAxisLabel,
  67. const QString &yAxisLabel)
  68. {
  69. // 设置图表标题
  70. m_chart->setTitle(chartTitle);
  71. // 设置 X 轴和 Y 轴标题
  72. m_axisX->setTitleText(xAxisLabel);
  73. m_axisY->setTitleText(yAxisLabel);
  74. }
  75. void ChartLine::addDataSeries(const DataSeries &series)
  76. {
  77. if (m_dataSeriesMap.contains(series.seriesName)) {
  78. qDebug() << "Series already exists:" << series.seriesName;
  79. return;
  80. }
  81. // 存储系列信息
  82. m_dataSeriesMap.insert(series.seriesName, series);
  83. // 创建对应的 QScatterSeries
  84. QScatterSeries* scatter = new QScatterSeries();
  85. scatter->setName(series.seriesName + "_scatter");
  86. // 隐藏 scatter series markers
  87. scatter->setMarkerSize(0.0);
  88. scatter->setPen(Qt::NoPen);
  89. scatter->setBrush(Qt::NoBrush);
  90. // 添加到图表并绑定坐标轴
  91. m_chart->addSeries(scatter);
  92. scatter->attachAxis(m_axisX);
  93. scatter->attachAxis(m_axisY);
  94. // 存储 scatter 系列
  95. m_scatterSeriesMap.insert(series.seriesName, scatter);
  96. // 更新散点数据
  97. scatter->replace(series.data);
  98. // 创建自定义图标
  99. QList<QGraphicsPixmapItem*> pixmapList;
  100. for (const QPointF &point : series.data) {
  101. QPointF position = m_chart->mapToPosition(point, m_lineSeries);
  102. QGraphicsPixmapItem *pixmapItem = new QGraphicsPixmapItem(series.markerIcon);
  103. pixmapItem->setPos(position - QPointF(series.markerIcon.width() / 2, series.markerIcon.height() / 2));
  104. pixmapItem->setParentItem(m_chart);
  105. pixmapList.append(pixmapItem);
  106. }
  107. m_pixmapItemsMap.insert(series.seriesName, pixmapList);
  108. // 重新构建折线数据
  109. rebuildLineSeries();
  110. }
  111. void ChartLine::removeDataSeries(const QString &seriesName)
  112. {
  113. if (!m_dataSeriesMap.contains(seriesName)) {
  114. qDebug() << "Series does not exist:" << seriesName;
  115. return;
  116. }
  117. // 移除系列信息
  118. m_dataSeriesMap.remove(seriesName);
  119. // 移除对应的 scatter 系列
  120. if (m_scatterSeriesMap.contains(seriesName)) {
  121. QScatterSeries* scatter = m_scatterSeriesMap.value(seriesName);
  122. m_chart->removeSeries(scatter);
  123. delete scatter;
  124. m_scatterSeriesMap.remove(seriesName);
  125. }
  126. // 移除并删除自定义图标
  127. if (m_pixmapItemsMap.contains(seriesName)) {
  128. for (QGraphicsPixmapItem* pixmap : m_pixmapItemsMap[seriesName]) {
  129. m_chart->scene()->removeItem(pixmap);
  130. delete pixmap;
  131. }
  132. m_pixmapItemsMap.remove(seriesName);
  133. }
  134. // 重新构建折线数据
  135. rebuildLineSeries();
  136. }
  137. void ChartLine::updateDataSeries(const QString &seriesName, const QList<QPointF> &data)
  138. {
  139. if (!m_dataSeriesMap.contains(seriesName)) {
  140. qDebug() << "Series does not exist:" << seriesName;
  141. return;
  142. }
  143. // 更新数据
  144. m_dataSeriesMap[seriesName].data = data;
  145. // 更新对应的 scatter 系列
  146. if (m_scatterSeriesMap.contains(seriesName)) {
  147. QScatterSeries* scatter = m_scatterSeriesMap.value(seriesName);
  148. scatter->replace(data);
  149. }
  150. // 更新自定义图标位置
  151. if (m_pixmapItemsMap.contains(seriesName)) {
  152. const QList<QGraphicsPixmapItem*> &pixmaps = m_pixmapItemsMap[seriesName];
  153. QList<QPointF> &seriesData = m_dataSeriesMap[seriesName].data;
  154. int minSize = qMin(pixmaps.size(), seriesData.size());
  155. for (int i = 0; i < minSize; ++i) {
  156. QPointF position = m_chart->mapToPosition(seriesData[i], m_lineSeries);
  157. pixmaps[i]->setPos(position - QPointF(pixmaps[i]->pixmap().width() / 2, pixmaps[i]->pixmap().height() / 2));
  158. }
  159. // 移除多余的 pixmap
  160. if (pixmaps.size() > seriesData.size()) {
  161. for (int i = seriesData.size(); i < pixmaps.size(); ++i) {
  162. m_chart->scene()->removeItem(pixmaps[i]);
  163. delete pixmaps[i];
  164. }
  165. QList<QGraphicsPixmapItem*> updatedList;
  166. for (int i = 0; i < seriesData.size(); ++i) {
  167. updatedList.append(pixmaps[i]);
  168. }
  169. m_pixmapItemsMap[seriesName] = updatedList;
  170. }
  171. // 添加缺失的 pixmap
  172. else if (pixmaps.size() < seriesData.size()) {
  173. for (int i = pixmaps.size(); i < seriesData.size(); ++i) {
  174. QPointF position = m_chart->mapToPosition(seriesData[i], m_lineSeries);
  175. QGraphicsPixmapItem *pixmapItem = new QGraphicsPixmapItem(m_dataSeriesMap[seriesName].markerIcon);
  176. pixmapItem->setPos(position - QPointF(m_dataSeriesMap[seriesName].markerIcon.width() / 2, m_dataSeriesMap[seriesName].markerIcon.height() / 2));
  177. pixmapItem->setParentItem(m_chart);
  178. m_pixmapItemsMap[seriesName].append(pixmapItem);
  179. }
  180. }
  181. }
  182. // 重新构建折线数据
  183. rebuildLineSeries();
  184. }
  185. void ChartLine::rebuildLineSeries()
  186. {
  187. // 清空当前折线数据
  188. m_lineSeries->clear();
  189. // 汇总所有数据点
  190. QList<QPointF> allPoints;
  191. for (const auto &series : m_dataSeriesMap) {
  192. allPoints.append(series.data);
  193. }
  194. // 排序数据点以确保折线正确
  195. std::sort(allPoints.begin(), allPoints.end(), [](const QPointF &a, const QPointF &b) {
  196. return a.x() < b.x();
  197. });
  198. // 添加到折线系列
  199. m_lineSeries->replace(allPoints);
  200. // 更新自定义图标位置
  201. updateMarkers();
  202. }
  203. void ChartLine::updateMarkers()
  204. {
  205. for (auto it = m_pixmapItemsMap.begin(); it != m_pixmapItemsMap.end(); ++it) {
  206. const QString &seriesName = it.key();
  207. const QList<QPointF> &data = m_dataSeriesMap[seriesName].data;
  208. const QList<QGraphicsPixmapItem*> &pixmaps = it.value();
  209. for (int i = 0; i < data.size() && i < pixmaps.size(); ++i) {
  210. QPointF position = m_chart->mapToPosition(data[i], m_lineSeries);
  211. pixmaps[i]->setPos(position - QPointF(pixmaps[i]->pixmap().width() / 2, pixmaps[i]->pixmap().height() / 2));
  212. }
  213. }
  214. }
  215. void ChartLine::resizeEvent(QResizeEvent *event)
  216. {
  217. QChartView::resizeEvent(event);
  218. updateMarkers();
  219. }