默认暗色模式,添加值显示开关
This commit is contained in:
@@ -52,6 +52,14 @@ void BasicPlot::set_data(const QVector<PointData>& data)const {
|
||||
pimpl->set_data(data);
|
||||
}
|
||||
|
||||
void BasicPlot::set_labels_visible(bool visible) const {
|
||||
pimpl->set_labels_visible(visible);
|
||||
}
|
||||
|
||||
bool BasicPlot::labels_visible() const {
|
||||
return pimpl->labels_visible();
|
||||
}
|
||||
|
||||
bool BasicPlot::is_initialized() const {
|
||||
return pimpl->is_plot_initialized();
|
||||
}
|
||||
@@ -86,4 +94,4 @@ using namespace creeper;
|
||||
|
||||
void creeper::HeatMapPlot::paintEvent(QPaintEvent* event) {
|
||||
BasicPlot::paintEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,9 @@ public:
|
||||
void set_matrix_size(const int& w, const int& h)const;
|
||||
void set_data(const QVector<PointData>& data)const;
|
||||
void set_color_gradient_range(const double& min, const double& max)const;
|
||||
void set_labels_visible(bool visible) const;
|
||||
QSize get_matrix_size() const;
|
||||
bool labels_visible() const;
|
||||
bool is_initialized() const;
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -19,7 +19,13 @@
|
||||
using namespace creeper::plot_widget::internal;
|
||||
|
||||
struct BasicPlot::Impl {
|
||||
explicit Impl(BasicPlot& self) noexcept : self{self}, initialized(false), matrix_size(QSize{3, 4}) {}
|
||||
explicit Impl(BasicPlot& self) noexcept
|
||||
: matrix_size(QSize{3, 4})
|
||||
, color_min(0.0)
|
||||
, color_max(800.0)
|
||||
, show_labels(false)
|
||||
, initialized(false)
|
||||
, self{self} { }
|
||||
|
||||
public:
|
||||
std::optional<creeper::ColorScheme> scheme;
|
||||
@@ -41,10 +47,15 @@ public:
|
||||
|
||||
auto set_matrix_size(const QSize& size) -> void {
|
||||
matrix_size = size;
|
||||
const int expected = std::max(0, matrix_size.width() * matrix_size.height());
|
||||
last_values.assign(static_cast<std::size_t>(expected), 0.0);
|
||||
if (initialized) {
|
||||
reset_plot();
|
||||
if (!data_points.isEmpty()) {
|
||||
set_data(data_points);
|
||||
} else if (show_labels) {
|
||||
sync_labels(last_values);
|
||||
self.replot();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,6 +86,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
auto set_labels_visible(bool visible) -> void {
|
||||
show_labels = visible;
|
||||
if (initialized) {
|
||||
sync_labels(last_values);
|
||||
self.replot();
|
||||
}
|
||||
}
|
||||
|
||||
auto labels_visible() const -> bool {
|
||||
return show_labels;
|
||||
}
|
||||
|
||||
auto initialize_plot() -> void {
|
||||
if (initialized) return;
|
||||
|
||||
@@ -149,12 +172,12 @@ public:
|
||||
|
||||
auto reset_plot() -> void {
|
||||
// 清除所有绘图元素
|
||||
clear_labels();
|
||||
self.clearPlottables();
|
||||
self.clearGraphs();
|
||||
self.clearItems();
|
||||
self.clearFocus();
|
||||
color_map = nullptr;
|
||||
cell_labels.clear();
|
||||
|
||||
// 重新初始化
|
||||
initialized = false;
|
||||
@@ -163,7 +186,7 @@ public:
|
||||
auto update_plot_data() -> void {
|
||||
if (!initialized || !color_map) return;
|
||||
|
||||
ensure_labels();
|
||||
// ensure_labels();
|
||||
|
||||
const int width = matrix_size.width();
|
||||
const int height = matrix_size.height();
|
||||
@@ -182,7 +205,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
update_label_values(values);
|
||||
last_values = values;
|
||||
sync_labels(last_values);
|
||||
|
||||
// 重绘
|
||||
self.replot();
|
||||
@@ -201,8 +225,10 @@ private:
|
||||
QString ylabel;
|
||||
QSize matrix_size;
|
||||
QVector<PointData> data_points;
|
||||
std::vector<double> last_values;
|
||||
double color_min = 0.0;
|
||||
double color_max = 800.0;
|
||||
bool show_labels = false;
|
||||
bool initialized;
|
||||
BasicPlot& self;
|
||||
QCPColorScale* color_scale = nullptr;
|
||||
@@ -217,7 +243,7 @@ private:
|
||||
text_color = scheme->on_surface;
|
||||
}
|
||||
}
|
||||
label_text_color = QColor(0, 0, 0); // 固定黑色
|
||||
label_text_color = text_color;
|
||||
|
||||
const auto pen = QPen(text_color);
|
||||
|
||||
@@ -293,7 +319,6 @@ private:
|
||||
void update_label_values(const std::vector<double>& values) {
|
||||
const int width = matrix_size.width();
|
||||
const int height = matrix_size.height();
|
||||
const double range = std::max(color_max - color_min, 1.0);
|
||||
const int expected = width * height;
|
||||
for (int idx = 0; idx < expected && idx < cell_labels.size(); ++idx) {
|
||||
auto* label = cell_labels[idx];
|
||||
@@ -309,6 +334,18 @@ private:
|
||||
label->position->setCoords(x + 0.5, y + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
void sync_labels(const std::vector<double>& values) {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
if (show_labels) {
|
||||
ensure_labels();
|
||||
update_label_values(values);
|
||||
} else if (!cell_labels.isEmpty()) {
|
||||
clear_labels();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // TOUCHSENSOR_HEATMAP_IMPL_HH
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "line_chart.hh"
|
||||
#include <QLinearGradient>
|
||||
#include <QMargins>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
@@ -86,6 +87,16 @@ void LinePlot::initialize_plot() {
|
||||
graph_->setAntialiased(true);
|
||||
graph_->setAdaptiveSampling(true);
|
||||
|
||||
current_label_ = new QCPItemText(this);
|
||||
current_label_->position->setType(QCPItemPosition::ptAxisRectRatio);
|
||||
current_label_->setPositionAlignment(Qt::AlignRight | Qt::AlignTop);
|
||||
current_label_->position->setCoords(0.98, 0.04);
|
||||
current_label_->setPadding(QMargins(6, 3, 6, 3));
|
||||
current_label_->setBrush(QColor(0, 0, 0, 50));
|
||||
current_label_->setPen(Qt::NoPen);
|
||||
current_label_->setLayer("overlay");
|
||||
current_label_->setClipToAxisRect(true);
|
||||
|
||||
initialized_ = true;
|
||||
apply_theme();
|
||||
update_graph();
|
||||
@@ -100,6 +111,7 @@ void LinePlot::apply_theme() {
|
||||
QColor line_color{ 16, 54, 128 };
|
||||
QColor text_color{ 30, 30, 30 };
|
||||
QColor bg_color{ 232, 238, 248 };
|
||||
QColor label_bg = QColor(0, 0, 0, 50);
|
||||
if (scheme_.has_value()) {
|
||||
if (scheme_->primary.isValid()) {
|
||||
line_color = scheme_->primary;
|
||||
@@ -116,6 +128,11 @@ void LinePlot::apply_theme() {
|
||||
else if (scheme_->surface.isValid()) {
|
||||
bg_color = scheme_->surface;
|
||||
}
|
||||
if (scheme_->surface_container.isValid()) {
|
||||
label_bg = QColor(scheme_->surface_container.red(),
|
||||
scheme_->surface_container.green(),
|
||||
scheme_->surface_container.blue(), 90);
|
||||
}
|
||||
}
|
||||
|
||||
QColor grid_color = bg_color;
|
||||
@@ -150,6 +167,14 @@ void LinePlot::apply_theme() {
|
||||
scatter.setSize(7);
|
||||
graph_->setScatterStyle(scatter);
|
||||
}
|
||||
|
||||
if (current_label_) {
|
||||
current_label_->setColor(text_color);
|
||||
current_label_->setBrush(label_bg);
|
||||
QFont f = current_label_->font();
|
||||
f.setBold(true);
|
||||
current_label_->setFont(f);
|
||||
}
|
||||
}
|
||||
|
||||
void LinePlot::update_graph() {
|
||||
@@ -164,6 +189,9 @@ void LinePlot::update_graph() {
|
||||
if (points_.isEmpty()) {
|
||||
graph_->data()->clear();
|
||||
reset_graph_range();
|
||||
if (current_label_) {
|
||||
current_label_->setText(QStringLiteral("--"));
|
||||
}
|
||||
replot();
|
||||
return;
|
||||
}
|
||||
@@ -203,6 +231,11 @@ void LinePlot::update_graph() {
|
||||
yAxis->setRange(min_val - padding, max_val + padding);
|
||||
}
|
||||
|
||||
if (current_label_) {
|
||||
const double last_val = points_.back().y();
|
||||
current_label_->setText(QString::number(last_val, 'f', 1));
|
||||
}
|
||||
|
||||
replot();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "qcustomplot/qcustomplot.h"
|
||||
#include <QPaintEvent>
|
||||
#include <QPointF>
|
||||
#include <QString>
|
||||
#include <concepts>
|
||||
#include <optional>
|
||||
#include <qsize.h>
|
||||
@@ -43,6 +44,7 @@ class LinePlot: public QCustomPlot {
|
||||
bool initialized_ = false;
|
||||
std::optional<ColorScheme> scheme_;
|
||||
QCPGraph* graph_ = nullptr;
|
||||
QCPItemText* current_label_ = nullptr;
|
||||
int max_points_ = 240;
|
||||
double default_y_range_ = 100.0;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <QLinearGradient>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QPointF>
|
||||
|
||||
using creeper::vector_widget::internal::VectorPlot;
|
||||
|
||||
@@ -45,6 +49,116 @@ void VectorPlot::paintEvent(QPaintEvent* event) {
|
||||
initialize_plot();
|
||||
}
|
||||
QCustomPlot::paintEvent(event);
|
||||
|
||||
// Custom glossy arrow rendering
|
||||
const auto rect = axisRect();
|
||||
if (!rect) {
|
||||
return;
|
||||
}
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
const QRectF plot_rect = rect->rect();
|
||||
const double side_pad = plot_rect.width() * 0.24;
|
||||
QRectF area = plot_rect.adjusted(side_pad, 8.0, -side_pad, -8.0);
|
||||
const double cx_canvas = area.center().x();
|
||||
const double cy_canvas = area.center().y();
|
||||
const double scale = 0.72; // overall shrink to make it slimmer
|
||||
area.setWidth(area.width() * scale);
|
||||
area.setHeight(area.height() * scale);
|
||||
area.moveCenter(QPointF(cx_canvas, cy_canvas));
|
||||
if (area.width() <= 0.0 || area.height() <= 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const double w = area.width();
|
||||
const double h = area.height();
|
||||
const double cx = area.center().x();
|
||||
const double shaft_w = w * 0.18;
|
||||
const double shaft_r = shaft_w * 0.25;
|
||||
const double head_h = h * 0.36;
|
||||
const double head_w = w * 0.52;
|
||||
const double shaft_h = h - head_h;
|
||||
const double shaft_x = cx - shaft_w * 0.5;
|
||||
const double shaft_y = area.top();
|
||||
const double head_base_y = shaft_y + shaft_h - shaft_r * 0.4; // overlap slightly to avoid seam
|
||||
|
||||
QPainterPath shaft;
|
||||
shaft.addRoundedRect(QRectF(shaft_x, shaft_y, shaft_w, shaft_h), shaft_r, shaft_r);
|
||||
|
||||
QPainterPath head;
|
||||
head.moveTo(cx - head_w * 0.5, head_base_y);
|
||||
head.lineTo(cx + head_w * 0.5, head_base_y);
|
||||
head.lineTo(cx, area.bottom());
|
||||
head.closeSubpath();
|
||||
|
||||
QPainterPath arrow = shaft.united(head);
|
||||
|
||||
// Vibrant orange palette (fixed)
|
||||
QColor base_color(255, 140, 0);
|
||||
QColor highlight = base_color.lighter(165);
|
||||
QColor mid = base_color;
|
||||
QColor shadow = base_color.darker(180);
|
||||
|
||||
QLinearGradient body_grad(area.topLeft(), QPointF(area.left(), area.bottom()));
|
||||
body_grad.setColorAt(0.0, highlight);
|
||||
body_grad.setColorAt(0.28, mid);
|
||||
body_grad.setColorAt(0.72, base_color.darker(110));
|
||||
body_grad.setColorAt(1.0, shadow);
|
||||
|
||||
const double angle_deg = std::atan2(arrow_dir_.y(), arrow_dir_.x()) * 180.0 / 3.14159265358979323846 - 90.0;
|
||||
QTransform transform;
|
||||
transform.translate(cx, (shaft_y + head_base_y + area.bottom()) / 3.0); // approximate center
|
||||
transform.rotate(angle_deg);
|
||||
transform.translate(-cx, -(shaft_y + head_base_y + area.bottom()) / 3.0);
|
||||
|
||||
auto draw_with_transform = [&](const QPainterPath& path, const QBrush& brush, const QPen* pen = nullptr) {
|
||||
const QPainterPath rotated = transform.map(path);
|
||||
painter.setBrush(brush);
|
||||
if (pen) {
|
||||
painter.setPen(*pen);
|
||||
}
|
||||
else {
|
||||
painter.setPen(Qt::NoPen);
|
||||
}
|
||||
painter.drawPath(rotated);
|
||||
};
|
||||
|
||||
draw_with_transform(arrow, QBrush(body_grad));
|
||||
|
||||
// Gloss highlight
|
||||
QPainterPath gloss;
|
||||
const double gloss_w = shaft_w * 0.42;
|
||||
QRectF gloss_rect(cx - gloss_w * 0.5, shaft_y + h * 0.04, gloss_w, shaft_h * 0.5);
|
||||
gloss.addRoundedRect(gloss_rect, gloss_w * 0.4, gloss_w * 0.4);
|
||||
QLinearGradient gloss_grad(gloss_rect.topLeft(), gloss_rect.bottomLeft());
|
||||
QColor gloss_hi = Qt::white;
|
||||
gloss_hi.setAlpha(190);
|
||||
QColor gloss_lo = Qt::white;
|
||||
gloss_lo.setAlpha(40);
|
||||
gloss_grad.setColorAt(0.0, gloss_hi);
|
||||
gloss_grad.setColorAt(1.0, gloss_lo);
|
||||
draw_with_transform(gloss, QBrush(gloss_grad));
|
||||
|
||||
// Head specular highlights
|
||||
const double spec_w = head_w * 0.18;
|
||||
QRectF spec_left(cx - head_w * 0.32, head_base_y + head_h * 0.08, spec_w, head_h * 0.2);
|
||||
QRectF spec_right(cx + head_w * 0.14, head_base_y + head_h * 0.1, spec_w * 0.8, head_h * 0.2);
|
||||
auto paint_spec = [&](const QRectF& r) {
|
||||
QPainterPath p;
|
||||
p.addRoundedRect(r, r.width() * 0.4, r.height() * 0.6);
|
||||
QLinearGradient g(r.topLeft(), r.bottomLeft());
|
||||
QColor hi = Qt::white;
|
||||
hi.setAlpha(180);
|
||||
QColor lo = Qt::white;
|
||||
lo.setAlpha(30);
|
||||
g.setColorAt(0.0, hi);
|
||||
g.setColorAt(1.0, lo);
|
||||
draw_with_transform(p, QBrush(g));
|
||||
};
|
||||
paint_spec(spec_left);
|
||||
paint_spec(spec_right);
|
||||
}
|
||||
|
||||
void VectorPlot::initialize_plot() {
|
||||
@@ -109,6 +223,7 @@ void VectorPlot::apply_color_scheme() {
|
||||
strong_pen.setJoinStyle(Qt::MiterJoin);
|
||||
if (primary_arrow_) {
|
||||
primary_arrow_->setPen(strong_pen);
|
||||
primary_arrow_->setVisible(false); // 使用自绘 3D 箭头
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +293,7 @@ void VectorPlot::update_vectors() {
|
||||
}
|
||||
dir_x /= dir_len;
|
||||
dir_y /= dir_len;
|
||||
arrow_dir_ = QPointF(dir_x, dir_y);
|
||||
const double arrow_len = 0.48 * std::min(width, height); // 稍长的指针
|
||||
const double tail_ratio = 0.25; // 穿过中心的尾巴略长
|
||||
const double tail_len = arrow_len * tail_ratio;
|
||||
@@ -189,7 +305,7 @@ void VectorPlot::update_vectors() {
|
||||
if (primary_arrow_) {
|
||||
primary_arrow_->start->setCoords(cx - dir_x * tail_len, cy - dir_y * tail_len);
|
||||
primary_arrow_->end->setCoords(cx + dir_x * head_base, cy + dir_y * head_base);
|
||||
primary_arrow_->setVisible(true);
|
||||
primary_arrow_->setVisible(false); // 位置保留以备需要,但当前使用自绘 3D 箭头
|
||||
}
|
||||
|
||||
replot();
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <QPaintEvent>
|
||||
#include <concepts>
|
||||
#include <qsize.h>
|
||||
#include <qpoint.h>
|
||||
#include <qvector.h>
|
||||
|
||||
namespace creeper {
|
||||
@@ -39,12 +40,13 @@ class VectorPlot : public QCustomPlot {
|
||||
void ensure_arrows();
|
||||
void apply_color_scheme();
|
||||
|
||||
QSize matrix_size_{ 3, 4 };
|
||||
QVector<PointData> data_points_;
|
||||
bool initialized_ = false;
|
||||
QSize matrix_size_{ 3, 4 };
|
||||
QVector<PointData> data_points_;
|
||||
bool initialized_ = false;
|
||||
std::optional<ColorScheme> scheme_;
|
||||
QColor arrow_color_{ 16, 54, 128 }; // 深蓝色
|
||||
QCPItemLine* primary_arrow_ = nullptr;
|
||||
QColor arrow_color_{ 16, 54, 128 }; // 深蓝色
|
||||
QPointF arrow_dir_{ 0.0, 1.0 };
|
||||
QCPItemLine* primary_arrow_ = nullptr;
|
||||
|
||||
void ensure_primary_arrow();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user