改bug
This commit is contained in:
@@ -18,7 +18,30 @@ struct Graph_WebSocket::Private {
|
||||
Graph_WebSocket::Graph_WebSocket(drogon::WebSocketConnectionPtr connection, std::shared_ptr<Plot> plot) : d(std::make_unique<Private>()) { d->connection = connection; d->plot = std::move(plot); d->owner = connection.get(); }
|
||||
Graph_WebSocket::~Graph_WebSocket() { close(); }
|
||||
void Graph_WebSocket::start() { if (d->attached) return; const auto weak = weak_from_this(); d->plot->attach(d->owner, [weak](std::string pixels) { const auto socket = weak.lock(); if (!socket) return; const auto connection = socket->d->connection.lock(); if (connection && connection->connected()) connection->send(pixels.data(), pixels.size(), drogon::WebSocketMessageType::Binary); }); d->attached = true; }
|
||||
void Graph_WebSocket::receive(std::string_view message) { const auto json = nlohmann::json::parse(message, nullptr, false); if (json.is_discarded() || !json.is_object()) return; Plot_Event event; if (const auto value = json.find("time"); value != json.end() && value->is_number()) event.time_milliseconds = value->get<double>(); if (const auto value = json.find("width"); value != json.end() && value->is_number_unsigned()) event.width = std::clamp(value->get<std::uint32_t>(), 160U, 1920U); if (const auto value = json.find("height"); value != json.end() && value->is_number_unsigned()) event.height = std::clamp(value->get<std::uint32_t>(), 120U, 1080U); d->plot->submit(event); }
|
||||
void Graph_WebSocket::receive(std::string_view message) {
|
||||
const auto json = nlohmann::json::parse(message, nullptr, false);
|
||||
if (json.is_discarded() || !json.is_object()) return;
|
||||
Plot_Event event;
|
||||
if (const auto value = json.find("time"); value != json.end() && value->is_number())
|
||||
event.time_milliseconds = value->get<double>();
|
||||
if (const auto value = json.find("width"); value != json.end() && value->is_number_unsigned())
|
||||
event.width = std::clamp(value->get<std::uint32_t>(), 160U, 1920U);
|
||||
if (const auto value = json.find("height"); value != json.end() && value->is_number_unsigned())
|
||||
event.height = std::clamp(value->get<std::uint32_t>(), 120U, 1080U);
|
||||
if (const auto value = json.find("wheel"); value != json.end() && value->is_object()) {
|
||||
const auto x = value->find("x");
|
||||
const auto y = value->find("y");
|
||||
const auto delta_y = value->find("delta_y");
|
||||
if (x != value->end() && x->is_number() && y != value->end() && y->is_number()
|
||||
&& delta_y != value->end() && delta_y->is_number()) {
|
||||
event.wheel = Plot_Wheel_Event{
|
||||
std::clamp(x->get<double>(), 0.0, static_cast<double>(event.width)),
|
||||
std::clamp(y->get<double>(), 0.0, static_cast<double>(event.height)),
|
||||
std::clamp(delta_y->get<double>(), -120.0, 120.0)};
|
||||
}
|
||||
}
|
||||
d->plot->submit(event);
|
||||
}
|
||||
void Graph_WebSocket::close() { if (!d->attached) return; d->plot->detach(d->owner); d->attached = false; }
|
||||
|
||||
Graph_WebSocket_Controller::Graph_WebSocket_Controller(Plot_Resolver resolver) : resolve_plot(std::move(resolver)) {}
|
||||
|
||||
+40
-6
@@ -14,6 +14,7 @@
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <numbers>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
@@ -172,7 +173,21 @@ Time_Axis_Object::Builder time_axis_builder(
|
||||
|
||||
template <typename... Axes>
|
||||
void resize_axes(Size viewport, Axes*... axes) {
|
||||
(axes->template set<&Abs_Axis::Prop::canvas_size>(viewport), ...);
|
||||
const double left = std::clamp(static_cast<double>(viewport.width) * 0.10, 42.0, 68.0);
|
||||
const double right = std::clamp(static_cast<double>(viewport.width) * 0.05, 18.0, 34.0);
|
||||
const double top = std::clamp(static_cast<double>(viewport.height) * 0.07, 16.0, 30.0);
|
||||
const double bottom = std::clamp(static_cast<double>(viewport.height) * 0.13, 36.0, 52.0);
|
||||
const Point_F origin{left, static_cast<double>(viewport.height) - bottom};
|
||||
const Axis_Pixel_Length horizontal_length = std::max(1.0, static_cast<double>(viewport.width) - left - right);
|
||||
const Axis_Pixel_Length vertical_length = -std::max(1.0, static_cast<double>(viewport.height) - top - bottom);
|
||||
const auto resize_axis = [&](auto* axis) {
|
||||
const auto orientation = axis->template read_prop<Abs_Axis::Base_Tag>().orientation;
|
||||
axis->template set<&Abs_Axis::Prop::canvas_size>(viewport);
|
||||
axis->template set<&Abs_Axis::Prop::position>(origin);
|
||||
axis->template set<&Abs_Axis::Prop::pixel_length>(
|
||||
orientation == Axis_Orientation::horizontal ? horizontal_length : vertical_length);
|
||||
};
|
||||
(resize_axis(axes), ...);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -361,14 +376,16 @@ std::shared_ptr<Plot> make_waterfall_plot(asio::any_io_executor executor) {
|
||||
.set(&Render_Scene_2D::Prop::view_active, true);
|
||||
scene_builder.add_renderable(waterfall.get());
|
||||
auto scene = *scene_builder.build();
|
||||
auto update = [raw = waterfall.get(), frequency = frequency.get(), time = time.get(), tick = std::uint64_t{}](const Plot_Event& event) mutable {
|
||||
auto update = [raw = waterfall.get(), frequency = frequency.get(), time = time.get()](const Plot_Event& event) {
|
||||
resize_axes({static_cast<int>(event.width), static_cast<int>(event.height)}, frequency, time);
|
||||
std::array<double, 192> values{};
|
||||
for (std::size_t i = 0; i < values.size(); ++i)
|
||||
values[i] = -100.0 + 70.0 * std::exp(-240.0 * std::pow(
|
||||
static_cast<double>(i) / values.size() - 0.5
|
||||
- 0.22 * std::sin(event.time_milliseconds * 0.0006), 2.0));
|
||||
raw->append_row(tick++, values);
|
||||
constexpr double day_milliseconds = 86'400'000.0;
|
||||
raw->append_row(Time_Of_Day{static_cast<std::int64_t>(
|
||||
std::fmod(std::max(0.0, event.time_milliseconds), day_milliseconds))}, values);
|
||||
};
|
||||
auto view = make_scene_view<
|
||||
Prop_Field<&Waterfall::Prop::tooltip_enabled, "tooltip_enabled", "Enables value inspection tooltips over waterfall cells.">,
|
||||
@@ -409,9 +426,20 @@ std::shared_ptr<Plot> make_constellation_plot(asio::any_io_executor executor) {
|
||||
auto scene = *scene_builder.build();
|
||||
auto update = [raw = constellation.get(), horizontal = horizontal.get(), vertical = vertical.get()](const Plot_Event& event) {
|
||||
resize_axes({static_cast<int>(event.width), static_cast<int>(event.height)}, horizontal, vertical);
|
||||
const double phase = event.time_milliseconds * 0.003;
|
||||
raw->append_point({std::cos(phase) * 0.82 + 0.04 * std::sin(phase * 7.0),
|
||||
std::sin(phase) * 0.82 + 0.04 * std::cos(phase * 5.0)});
|
||||
const auto& state = raw->template read_prop<Constellation_Diagram::Base_Tag>();
|
||||
const int anchor_count = static_cast<int>(state.type);
|
||||
const double radius = std::min(state.i_range.size(), state.q_range.size()) * 0.4;
|
||||
const double phase = event.time_milliseconds * 0.001;
|
||||
for (int index = 0; index < anchor_count; ++index) {
|
||||
const double angle = state.phase_offset_radians
|
||||
+ 2.0 * std::numbers::pi * static_cast<double>(index) / anchor_count;
|
||||
const double noise_i = 0.025 * std::sin(phase * 11.0 + index * 1.73)
|
||||
+ 0.012 * std::cos(phase * 23.0 + index * 0.61);
|
||||
const double noise_q = 0.025 * std::cos(phase * 13.0 + index * 1.37)
|
||||
+ 0.012 * std::sin(phase * 19.0 + index * 0.47);
|
||||
raw->append_point({state.i_range.center() + std::cos(angle) * radius + noise_i,
|
||||
state.q_range.center() + std::sin(angle) * radius + noise_q});
|
||||
}
|
||||
};
|
||||
auto view = make_scene_view<
|
||||
Prop_Field<&Constellation_Diagram::Prop::point_lifetime_ms, "point_lifetime_ms", "Time in milliseconds that an appended constellation point remains visible.">,
|
||||
@@ -538,6 +566,12 @@ void Plot::ensure_started() {
|
||||
if (auto* scene = std::get_if<std::unique_ptr<Scene_2D>>(&self->d->scene)) {
|
||||
(*scene)->set<&Render_Scene_2D::Prop::viewport>(
|
||||
Size{static_cast<int>(event.width), static_cast<int>(event.height)});
|
||||
if (event.wheel) {
|
||||
Wheel_Event wheel;
|
||||
wheel.position = {event.wheel->position_x, event.wheel->position_y};
|
||||
wheel.angle_delta_y = event.wheel->delta_y;
|
||||
(*scene)->dispatch_event(wheel);
|
||||
}
|
||||
(*scene)->render();
|
||||
} else {
|
||||
auto& scene_3d = std::get<std::unique_ptr<Scene_3D>>(self->d->scene);
|
||||
|
||||
@@ -6,13 +6,20 @@
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
namespace aethera::web {
|
||||
struct Plot_Wheel_Event {
|
||||
double position_x{}; /* Pointer position in the rendered viewport, in physical pixels. */
|
||||
double position_y{}; /* Pointer position in the rendered viewport, in physical pixels. */
|
||||
double delta_y{}; /* Normalized vertical wheel angle delta. */
|
||||
};
|
||||
struct Plot_Event {
|
||||
double time_milliseconds{};
|
||||
std::uint32_t width{720};
|
||||
std::uint32_t height{420};
|
||||
std::optional<Plot_Wheel_Event> wheel{}; /* Canvas interaction attached to this render request. */
|
||||
};
|
||||
class Plot final : public std::enable_shared_from_this<Plot> {
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user