Skip to main content

blockworx_canvas2d/
ground.rs

1//! The ground under the diagram: the canvas fill, then the grid over it.
2//!
3//! The rule is [`blockworx_paint::ground`]'s, so this and the egui backend
4//! rule the same lines at the same weights.
5
6use blockworx_geom::Rect;
7use blockworx_paint::ground::{GridLine, horizontals, verticals};
8use blockworx_paint::{Ground, Vantage};
9use web_sys::CanvasRenderingContext2d;
10
11use crate::color::css_color;
12
13/// Fill `viewport` and rule the grid `vantage` shows over it.
14pub fn paint_ground(
15    ctx: &CanvasRenderingContext2d,
16    viewport: Rect,
17    vantage: Vantage,
18    ground: Ground,
19) {
20    ctx.set_fill_style_str(&css_color(ground.background));
21    ctx.fill_rect(
22        viewport.min.x.into(),
23        viewport.min.y.into(),
24        viewport.width().into(),
25        viewport.height().into(),
26    );
27    if ground.grid.a() == 0 {
28        return;
29    }
30    ctx.set_stroke_style_str(&css_color(ground.grid));
31    // One path per weight: a sheet rules hundreds of lines, and each stroke
32    // of its own would be hundreds of round trips across the wasm boundary.
33    for weight in [GridLine::Major, GridLine::Minor] {
34        ctx.begin_path();
35        for x in at(verticals(vantage, viewport), weight) {
36            ctx.move_to(x.into(), viewport.min.y.into());
37            ctx.line_to(x.into(), viewport.max.y.into());
38        }
39        for y in at(horizontals(vantage, viewport), weight) {
40            ctx.move_to(viewport.min.x.into(), y.into());
41            ctx.line_to(viewport.max.x.into(), y.into());
42        }
43        ctx.set_line_width(weight.width().into());
44        ctx.stroke();
45    }
46}
47
48fn at(ruled: impl Iterator<Item = (f32, GridLine)>, weight: GridLine) -> impl Iterator<Item = f32> {
49    ruled
50        .filter(move |&(_, line)| line == weight)
51        .map(|(at, _)| at)
52}