fix(ui): 原数据散点 白底+散点项关联xTop轴(修x压缩)+过原点零线 + 色阶条等宽色带/深色文字/白底

This commit is contained in:
gaozheng 2026-06-11 15:55:32 +08:00
parent e405fc1565
commit 1f28505227
3 changed files with 46 additions and 40 deletions

View File

@ -19,68 +19,47 @@ void ColorBarWidget::setColorScale(const core::ColorScale& scale) {
} }
void ColorBarWidget::paintEvent(QPaintEvent* /*event*/) { void ColorBarWidget::paintEvent(QPaintEvent* /*event*/) {
auto stops = scale_.stops();
if (stops.empty()) return;
QPainter p(this); QPainter p(this);
p.setRenderHint(QPainter::Antialiasing, false); p.setRenderHint(QPainter::Antialiasing, false);
const int W = width(); const int W = width();
const int H = height(); const int H = height();
p.fillRect(0, 0, W, H, Qt::white); // 白底,对齐原版
auto stops = scale_.stops();
if (stops.size() < 2) return;
// 横向色带区域(顶部)
const int barY = 2; const int barY = 2;
const int barH = kBarHeight; const int barH = kBarHeight;
// 等宽色带:每相邻断点一格,等宽(对齐原版图例,非按值比例)。
const int nSeg = static_cast<int>(stops.size()) - 1;
auto segX = [&](int i) { return static_cast<int>(static_cast<double>(i) / nSeg * (W - 1)); };
// 边界值 for (int i = 0; i < nSeg; ++i) {
double minVal = stops.front().first; int xL = segX(i), xR = segX(i + 1);
double maxVal = stops.back().first;
double range = maxVal - minVal;
if (range <= 0.0) range = 1.0;
// 绘制每段色格(相邻断点间一格)
for (std::size_t i = 0; i + 1 < stops.size(); ++i) {
double posL = (stops[i].first - minVal) / range;
double posR = (stops[i + 1].first - minVal) / range;
int xL = static_cast<int>(posL * (W - 1));
int xR = static_cast<int>(posR * (W - 1));
if (xR <= xL) xR = xL + 1; if (xR <= xL) xR = xL + 1;
const auto& c = stops[i].second; const auto& c = stops[i].second;
p.fillRect(xL, barY, xR - xL, barH, QColor(c.r, c.g, c.b, c.a)); p.fillRect(xL, barY, xR - xL, barH, QColor(c.r, c.g, c.b, c.a));
} }
// 最后一段(末断点颜色填到边缘)
{
double posL = (stops.back().first - minVal) / range;
int xL = static_cast<int>(posL * (W - 1));
const auto& c = stops.back().second;
p.fillRect(xL, barY, W - xL, barH, QColor(c.r, c.g, c.b, c.a));
}
// 外边框 // 外边框
p.setPen(QPen(QColor(80, 80, 80), 1)); p.setPen(QPen(QColor(120, 120, 120), 1));
p.drawRect(0, barY, W - 1, barH - 1); p.drawRect(0, barY, W - 1, barH - 1);
// 刻度区(色带下方) // 边界值标签(深色文字,白底可见),在各分格边界下方。
QFont font = p.font(); QFont font = p.font();
font.setPixelSize(kFontSize); font.setPixelSize(kFontSize);
p.setFont(font); p.setFont(font);
p.setPen(QColor(200, 200, 200)); p.setPen(QColor(60, 60, 60));
QFontMetrics fm(font);
const int tickY = barY + barH + 1; const int tickY = barY + barH + 1;
for (int i = 0; i <= nSeg; ++i) {
for (const auto& [val, color] : stops) { int x = segX(i);
double pos = (val - minVal) / range;
int x = static_cast<int>(pos * (W - 1));
// 刻度短线
p.drawLine(x, tickY, x, tickY + kTickHeight); p.drawLine(x, tickY, x, tickY + kTickHeight);
// 数值文字(右对齐到刻度位置,避免越界) const QString label = QString::number(stops[i].first, 'g', 4);
QString label = QString::number(val, 'g', 4);
QFontMetrics fm(font);
int tw = fm.horizontalAdvance(label); int tw = fm.horizontalAdvance(label);
int tx = x - tw / 2; int tx = x - tw / 2;
if (tx < 0) tx = 0; if (tx < 0) tx = 0;
if (tx + tw > W) tx = W - tw; if (tx + tw > W) tx = W - tw;
p.drawText(tx, H - 1, label); p.drawText(tx, H - 2, label);
} }
} }

View File

@ -12,6 +12,7 @@
#include <qwt_plot_canvas.h> #include <qwt_plot_canvas.h>
#include <qwt_plot_panner.h> #include <qwt_plot_panner.h>
#include <qwt_plot_magnifier.h> #include <qwt_plot_magnifier.h>
#include <qwt_plot_marker.h>
namespace geopro::app { namespace geopro::app {
@ -58,8 +59,29 @@ RawDataChartView::RawDataChartView(QWidget* parent) : QWidget(parent) {
plot_->enableAxis(QwtPlot::xBottom, false); plot_->enableAxis(QwtPlot::xBottom, false);
plot_->enableAxis(QwtPlot::yLeft, true); plot_->enableAxis(QwtPlot::yLeft, true);
// 深色背景风格 // 白底浅色(对齐原版 web 图表,与 App 暗色主题独立):画布白、轴文字深灰。
plot_->setCanvasBackground(QBrush(QColor(30, 30, 30))); plot_->setCanvasBackground(QBrush(Qt::white));
plot_->setAutoFillBackground(true);
{
QPalette pal = plot_->palette();
pal.setColor(QPalette::Window, Qt::white);
pal.setColor(QPalette::WindowText, QColor(90, 90, 90));
pal.setColor(QPalette::Text, QColor(90, 90, 90));
plot_->setPalette(pal);
}
// 过原点零线(对齐原版 zerolinex=0 竖线 + y=0 横线 → "四象限"观感)。
auto* zeroX = new QwtPlotMarker();
zeroX->setLineStyle(QwtPlotMarker::VLine);
zeroX->setXValue(0.0);
zeroX->setLinePen(QColor(180, 180, 180), 1.0);
zeroX->setXAxis(QwtPlot::xTop);
zeroX->attach(plot_);
auto* zeroY = new QwtPlotMarker();
zeroY->setLineStyle(QwtPlotMarker::HLine);
zeroY->setYValue(0.0);
zeroY->setLinePen(QColor(180, 180, 180), 1.0);
zeroY->attach(plot_);
// 交互Panner左键拖动平移+ Magnifier滚轮缩放 // 交互Panner左键拖动平移+ Magnifier滚轮缩放
auto* panner = new QwtPlotPanner(plot_->canvas()); auto* panner = new QwtPlotPanner(plot_->canvas());

View File

@ -1,5 +1,6 @@
#include "panels/chart/ScatterPlotItem.hpp" #include "panels/chart/ScatterPlotItem.hpp"
#include <QPainter> #include <QPainter>
#include <qwt_plot.h>
#include <qwt_scale_map.h> #include <qwt_scale_map.h>
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
@ -10,6 +11,10 @@ ScatterPlotItem::ScatterPlotItem()
: QwtPlotItem() { : QwtPlotItem() {
setTitle("Scatter"); setTitle("Scatter");
setRenderHint(QwtPlotItem::RenderAntialiased, false); setRenderHint(QwtPlotItem::RenderAntialiased, false);
// 关联到 x 顶轴(原数据 x 轴在顶部;与 RawDataChartView 的 setAxisScale(xTop,...) 一致,
// 否则项默认用 xBottom 的(未设置/自动)刻度 → 散点被错误压缩)。
setXAxis(QwtPlot::xTop);
setYAxis(QwtPlot::yLeft);
} }
void ScatterPlotItem::setData(const core::ScatterField& field, ColorMapService* svc) { void ScatterPlotItem::setData(const core::ScatterField& field, ColorMapService* svc) {