Iced Canvas: Need a better way to pass variables into a canvas

I have an iced program that displays data on a canvas. All works. In the main app view function I call the canvas and pass in several variables that are state variables in the main app. To pass them in I have had to go through what I think is a very convoluted process. There must be a better way but I do not know what that is. Any assistance will be appreciated.

fn view(state: &AppState) -> iced::Element<'_, Message> {  

    let points2  = &state.graph_points;
    let x_labels2= &state.x_axis_labels;
    let y_labels2 = &state.y_axis_labels;
    let index_values2= &state.min_and_max_values;

    let graph_points = points2.to_vec();
    let x_axis_labels = x_labels2.to_vec();
    let y_axis_labels = y_labels2.to_vec();
    let min_and_max_values = index_values2.to_vec();
    let start_date_index = state.start_date_index;

    match state.screen {

        Screen::Loading => loading_view(),
        Screen::Welcome => welcome_view(),
        Screen::DisplayGraph => {

            canvas(LineGraphCanvas {graph_points, 
                                            x_axis_labels, 
                                            y_axis_labels, 
                                            min_and_max_values, 
                                            start_date_index})
                .width(Length::Fill)
                .height(Length::Fill)
                .into()
        }
    }
}

struct AppState {
    screen: Screen,
    start_dates: Vec<String>,
    graph_points: Vec<Point>,
    x_axis_labels: Vec<String>,
    y_axis_labels: Vec<String>,
    min_and_max_values: Vec<IndexDateClose>,
    start_date_index: usize,
    axes_end_values: Vec<AxesMinMaxValues>,
}

pub struct LineGraphCanvas {
    pub graph_points: Vec<Point>,
    pub x_axis_labels: Vec<String>,
    pub y_axis_labels: Vec<String>,
    pub min_and_max_values: Vec<IndexDateClose>,
    pub start_date_index: usize,
}

the app state is considered "input" data to the view, and iced allows the view to borrow the app state, that's what the lifetime 'a in Element<'a, ...> is for.

if you want to be lazy, the canvas program can simply borrow the whole AppState:

struct LineGraphCanvas<'a> {
    app_state: &'a AppState
}

but this is obviously not so "clean" a solution. instead, I would create a separate type to encapsulate the the graph data, and both the app state and canvas program can use this common type, something like this:

struct GraphData {
    pub graph_points: Vec<Point>,
    pub x_axis_labels: Vec<String>,
    pub y_axis_labels: Vec<String>,
    pub min_and_max_values: Vec<IndexDateClose>,
    pub start_date_index: usize,
}

struct AppState {
    graph_data: GraphData,
}

struct MyCanvasProgram<'a> {
    graph_data: &'a GraphData,
}

impl canvas::Program for MyCanvasProgram<'_> {
    //...
}

fn view(state: &AppState) -> Element<'_, Message> {
    //...
    canvas(MyCanvasProgram(&state.graph_data)).width(...).height(...).into()
}

or, a small variant of this solution, I can use &GraphData directly as the canvas program, then I may just rename GraphData to GraphCanvas:

struct GraphCanvas {
    pub graph_points: Vec<Point>,
    pub x_axis_labels: Vec<String>,
    pub y_axis_labels: Vec<String>,
    pub min_and_max_values: Vec<IndexDateClose>,
    pub start_date_index: usize,
}

struct AppState {
    graph: GraphCanvas,
}

impl canvas::Program for &GraphCanvas {
    //...
}

fn view(state: &AppState) -> Element<'_, Message> {
    //...
    canvas(&state.graph).width(...).height(...).into()
}

bottom line is, you don't have to duplicate the fields in both the app state and the canvas program, they can be reused. how you implement it is more of a personal taste.

Fantastic. I employed your suggestion using one structure for both main and canvas. Simplified the program. Thank you. Below are code segments.

struct AppState {
    screen: Screen,
    start_dates: Vec<String>,
    axes_end_values: Vec<AxesMinMaxValues>,
    graph: GraphCanvas,
}

pub struct GraphCanvas {
    pub graph_points: Vec<Point>,
    pub x_axis_labels: Vec<String>,
    pub y_axis_labels: Vec<String>,
    pub min_and_max_values: Vec<IndexDateClose>,
    pub start_date_index: usize,
}

fn boot() -> (AppState, Task<Message>) {

    let initial_values = AppState {
        screen: Screen::Loading,
        start_dates: Vec::new(),
        axes_end_values: Vec::new(),
        graph: {
            GraphCanvas { graph_points: Vec::new(), 
                          x_axis_labels: Vec::new(), 
                          y_axis_labels: Vec::new(), 
                          min_and_max_values: Vec::new(), 
                          start_date_index: 0 }
        }
    };

fn view(state: &AppState) -> iced::Element<'_, Message> {  

    match state.screen {
        Screen::Loading => loading_view(),
        Screen::Welcome => welcome_view(),
        Screen::DisplayGraph => {
            canvas(&state.graph)
                .width(Length::Fill)
                .height(Length::Fill)
                .into()
        }
    }
}

impl canvas::Program<Message> for &GraphCanvas {...}