Для чего нужна данная статья? :
- Для поиска компромисса между библиотеками визуализации данных из API.
Зачем Вам это уметь? :
- Научиться использовать HTTP-клиенты, такие как reqwest или ureq.
- Использовать библиотеку Plotters и Yew для построения графиков.
Установите зависимости plotters и yew-plotters (если они доступны). Если нет yew-plotters, то используйте plotters и сохраните изображение на диск, а затем отобразите его в компоненте Yew.
use plotters::prelude::*;
use serde::Deserialize;
use yew::prelude::*;
use yew::services::fetch::{FetchService, FetchTask, Request, Response};
use anyhow::Error;
#[derive(Deserialize, Debug)]
struct ApiResponse {
values: Vec<f64>,
}
struct Model {
link: ComponentLink<Self>,
fetch_task: Option<FetchTask>,
data: Option<ApiResponse>,
image_url: Option<String>,
}
enum Msg {
FetchData,
FetchReady(Result<ApiResponse, Error>),
RenderPlot,
}
impl Component for Model {
type Message = Msg;
type Properties = ();
fn create(ctx: &Context<Self>) -> Self {
Self {
link: ctx.link().clone(),
fetch_task: None,
data: None,
image_url: None,
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::FetchData => {
let request = Request::get("https://api.example.com/data")
.body(Ok(()))
.expect("Could not build request.");
let callback = ctx.link().callback(
|response: Response<Json<Result<ApiResponse, Error>>>| {
let Json(data) = response.into_body();
Msg::FetchReady(data)
},
);
let task = FetchService::fetch(request, callback).expect("failed to start request");
self.fetch_task = Some(task);
true
}
Msg::FetchReady(response) => {
self.data = response.ok();
self.fetch_task = None;
ctx.link().send_message(Msg::RenderPlot);
true
}
Msg::RenderPlot => {
if let Some(ref data) = self.data {
// Рендеринг графика с использованием Plotters
let file_path = "plot.png";
let root = BitMapBackend::new(file_path, (640, 480)).into_drawing_area();
root.fill(&WHITE).unwrap();
let mut chart = ChartBuilder::on(&root)
.caption("API Data Plot", ("sans-serif", 50))
.build_cartesian_2d(0..data.values.len(),
0.0..*data.values.iter().max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap())
.unwrap();
chart.draw_series(LineSeries::new(
data.values.iter().enumerate().map(|(x, y)| (x, *y)),
&RED,
)).unwrap();
root.present().unwrap();
// Задаем URL для отображения изображения
self.image_url = Some(file_path.to_string());
}
true
}
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
html! {
<div>
<button onclick={ctx.link().callback(|_| Msg::FetchData)}>{ "Fetch Data" }</button>
{ self.view_data() }
{ if let Some(ref url) = self.image_url {
html! {
<div>
<img src={url.clone()} alt="Plot"/>
</div>
}
} else {
html! {
<div>{ "No plot available" }</div>
}
}}
</div>
}
}
}
impl Model {
fn view_data(&self) -> Html {
if let Some(ref data) = self.data {
html! {
<div>
{ for data.values.iter().map(|value| html! { <p>{ value }</p> }) }
</div>
}
} else {
html! {
<div>{ "No data" }</div>
}
}
}
}
fn main() {
yew::start_app::<Model>();
}
Этот пример сохраняет изображение графика в файл и отображает его в компоненте Yew.