microBioRust_heatmap/canvas/
drawing.rs

1use web_sys::{CanvasRenderingContext2d, console};
2use wasm_bindgen::JsValue;
3
4
5pub fn draw_responsive_heatmap(
6    context: &CanvasRenderingContext2d,
7    values: Vec<Vec<i32>>,
8    x_labels: Vec<String>,
9    y_labels: Vec<String>,
10    canvas_width: f64,
11    canvas_height: f64,
12    device_pixel_ratio: f64,
13) -> Result<(), JsValue>
14{
15    let rows = values.len();
16    let cols = values[0].len();
17    console::log_1(&JsValue::from_str(&format!("up in the draw function")));
18    // Get canvas dimensions 
19    // Calculate dynamic padding and box size
20    let adj_canvas_width = canvas_width * device_pixel_ratio;
21    let adj_canvas_height = canvas_height * device_pixel_ratio;
22    let padding_left = adj_canvas_width * 0.05;
23    let padding_top = adj_canvas_height * 0.05;
24    let padding_bottom = adj_canvas_height * 0.05;
25    let _padding_right = adj_canvas_width * 0.05;
26
27  //  let box_width = (adj_canvas_width - padding_left - padding_right) / (cols as f64 * 1.1);
28  //  let box_height = (adj_canvas_height - padding_top - padding_bottom) / (rows as f64 * 1.1);
29   
30    let box_width = 30.0;
31    let box_height = 30.0;
32    // Clear the canvas
33    console::log_1(&JsValue::from_str(&format!("pad left {} pad bottom {}",&padding_left, &padding_bottom)));
34    context.clear_rect(0.0, 0.0, adj_canvas_width, adj_canvas_height);
35    println!("cleared rec");
36    // Draw the heatmap
37    for row in 0..rows {
38        for col in 0..cols {
39            let value = values[row][col];
40
41            // Set color based on value
42            let color = match value {
43                0 => "#fee0d2",
44                1 => "#fc9272",
45                2 => "#de2d26",
46                _ => "#FFFFFF",
47            };
48            //context.set_fill_style_str(&JsValue::from(color));
49	    context.set_fill_style_str(color);
50
51            let x = padding_left + (col as f64 * box_width);
52            let y = padding_top + (row as f64 * box_height);
53            context.fill_rect(x, y, box_width, box_height);
54
55            // Draw box borders
56            //context.set_stroke_style(&JsValue::from("#FFFFFF"));
57	    context.set_stroke_style_str("#FFFFFF");
58            context.set_line_width(2.0 / device_pixel_ratio);
59            
60            if row < rows - 1 {
61                context.begin_path();
62                context.move_to(x, y + box_height);
63                context.line_to(x + box_width, y + box_height);
64                context.stroke();
65            }
66
67            if col < cols - 1 {
68                context.begin_path();
69                context.move_to(x + box_width, y);
70                context.line_to(x + box_width, y + box_height);
71                context.stroke();
72            }
73        }
74    }
75    console::log_1(&JsValue::from_str(&format!(
76    "after the rows and cols padding bottom: {}, height: {}",
77         &padding_bottom,
78         &(box_height * rows as f64),
79            )));
80
81    // Draw X-axis
82    context.begin_path();
83    //context.set_stroke_style_str(&JsValue::from("#000000"));
84    context.set_stroke_style_str("#000000");
85    context.move_to(padding_left, (box_height * rows as f64) + padding_bottom);
86    context.line_to((box_height * rows as f64) + padding_bottom, (box_height * rows as f64) + padding_left);
87    context.stroke();
88    
89    // Draw Y-axis
90    context.begin_path();
91    context.move_to(padding_left, padding_top);
92    context.line_to(padding_left, (box_height * rows as f64) + padding_bottom);
93    context.stroke();
94
95    // Draw X-axis ticks and labels
96    let label_font_size = (box_height * 0.3).min(box_width * 0.3).max(12.0);
97    context.set_font(&format!("{}px Arial", label_font_size));
98    context.set_text_align("center");
99    context.set_text_baseline("top");
100    
101    for col in 0..cols {
102        let x = padding_left + col as f64 * box_width + box_width / 2.0;
103        let y = (box_height * rows as f64) + padding_bottom + 5.0;  // Position below the heatmap
104        context.fill_text(&x_labels[col], x, y)
105            .map_err(|_| JsValue::from_str(&format!("Failed to draw text at column {}", col)))?;
106
107        // Draw ticks
108        context.begin_path();
109        context.move_to(x, (box_height * rows as f64) + padding_bottom);
110        context.line_to(x, (box_height * rows as f64) + padding_bottom + 5.0);
111        context.stroke();
112    }
113
114    // Draw Y-axis ticks and labels
115    context.set_text_align("right");
116    context.set_text_baseline("middle");
117    
118    for row in 0..rows {
119        let x = padding_left - 10.0;  // Position to the left of the heatmap
120        let y = padding_top + row as f64 * box_height + box_height / 2.0;
121        context.fill_text(&y_labels[row], x, y)
122            .map_err(|_| JsValue::from_str(&format!("Failed to draw text at row {}", row)))?;
123
124        // Draw ticks
125        context.begin_path();
126        context.move_to(padding_left, y);
127        context.line_to(padding_left - 5.0, y);
128        context.stroke();
129    }
130    console::log_1(&JsValue::from_str(&format!(
131    "at the end of draw funct Canvas width: {}, height: {}",
132        &adj_canvas_width,
133        &adj_canvas_height
134         )));
135    Ok(())
136}