use bevy::{
input::common_conditions::input_just_pressed,
prelude::*,
render::{
render_asset::RenderAssetUsages,
render_resource::{Extent3d, TextureDimension, TextureFormat},
texture::Image,
},
};
use bevy_mod_plotters::prelude::*;
use plotters::prelude::*;
use plotters::prelude::{Circle, Text};
use rand::Rng;
const WIDTH: u32 = 500;
const HEIGHT: u32 = 500;
fn main() {
App::new()
.add_plugins((DefaultPlugins, PlottersPlugin))
.add_systems(Startup, setup)
.add_systems(
Update,
update_image.run_if(input_just_pressed(KeyCode::Space)),
)
.run();
}
fn setup(
mut commands: Commands,
mut images: ResMut<Assets<Image>>,
mut ui_materials: ResMut<Assets<PlotUiMaterial>>,
) {
let mut image = Image::new_fill(
Extent3d {
width: WIDTH,
height: HEIGHT,
depth_or_array_layers: 1,
},
TextureDimension::D2,
&[0x00, 0x00, 0x00, 0x00],
TextureFormat::Bgra8UnormSrgb,
RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD,
);
{
let root = try_as_backend(&mut image).unwrap().into_drawing_area();
let points = vec![(0.0, 0.0), (5.0, 5.0), (8.0, 7.0)];
hello_plot(&root, points).unwrap();
}
commands.spawn(Camera2dBundle::default());
commands
.spawn(NodeBundle {
style: Style {
width: Val::Percent(100.),
height: Val::Percent(100.),
justify_content: JustifyContent::Center,
..Default::default()
},
..Default::default()
})
.with_children(|parent| {
parent.spawn(MaterialNodeBundle {
style: Style {
width: Val::Px(WIDTH as f32),
height: Val::Px(HEIGHT as f32),
border: UiRect::all(Val::Px(20.0)),
..default()
},
material: ui_materials.add(PlotUiMaterial {
color: LinearRgba::WHITE,
texture: images.add(image),
}),
..default()
});
});
}
fn hello_plot<DB: DrawingBackend>(
root: &DrawingArea<DB, Shift>,
points: Vec<(f32, f32)>,
) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> {
root.fill(&WHITE)?;
let root = root.margin(30, 40, 30, 40);
let mut chart = ChartBuilder::on(&root)
.caption("Hello, Plot!", ("sans-serif", 40).into_font())
.x_label_area_size(20)
.y_label_area_size(40)
.build_cartesian_2d(0f32..10f32, 0f32..10f32)?;
chart
.configure_mesh()
.x_labels(5)
.y_labels(5)
.x_label_style(("sans-serif", 16))
.y_label_style(("sans-serif", 16))
.y_label_formatter(&|x| format!("{:.2}", x))
.draw()?;
chart.draw_series(LineSeries::new(points.clone(), &RED))?;
chart.draw_series(PointSeries::of_element(
points,
5,
&RED,
&|c, s, st| {
return EmptyElement::at(c) + Circle::new((0,0),s,st.filled()) + Text::new(format!("({:.1}, {:.1})", c.0, c.1), (10, 0), ("sans-serif", 16).into_font());
},
))?;
root.present()?;
Ok(())
}
fn update_image(
query: Query<&Handle<PlotUiMaterial>>,
mut ui_materials: ResMut<Assets<PlotUiMaterial>>,
mut images: ResMut<Assets<Image>>,
) {
let handle = query.single();
if let Some(material) = ui_materials.get_mut(handle) {
if let Some(image) = images.get_mut(&material.texture) {
let root = BitMapBackend::<BGRXPixel>::with_buffer_and_format(
&mut image.data,
(WIDTH, HEIGHT),
)
.unwrap()
.into_drawing_area();
let mut rng = rand::thread_rng();
let mut points = vec![];
for _ in 0..3 {
let x = rng.gen_range(0.0..10.0);
let y = rng.gen_range(0.0..10.0);
points.push((x, y));
}
hello_plot(&root, points).unwrap();
}
}
}