Skip to main content

ggplot_rs/render/
backend.rs

1use super::{Rect, RenderError};
2
3/// Point shape types.
4#[derive(Clone, Debug, Copy, PartialEq, Eq)]
5pub enum PointShape {
6    Circle,
7    Triangle,
8    Square,
9    Diamond,
10    Cross,
11    Plus,
12}
13
14impl PointShape {
15    /// All shapes in order (for discrete scale mapping).
16    pub const ALL: &[PointShape] = &[
17        PointShape::Circle,
18        PointShape::Triangle,
19        PointShape::Square,
20        PointShape::Diamond,
21        PointShape::Cross,
22        PointShape::Plus,
23    ];
24}
25
26/// Line type patterns.
27#[derive(Clone, Debug, Copy, PartialEq, Eq)]
28pub enum Linetype {
29    Solid,
30    Dashed,
31    Dotted,
32    DashDot,
33    LongDash,
34    TwoDash,
35}
36
37impl Linetype {
38    /// All linetypes in order (for discrete scale mapping).
39    pub const ALL: &[Linetype] = &[
40        Linetype::Solid,
41        Linetype::Dashed,
42        Linetype::Dotted,
43        Linetype::DashDot,
44        Linetype::LongDash,
45        Linetype::TwoDash,
46    ];
47
48    /// Get dash pattern as (draw_len, gap_len) pairs in pixels.
49    pub fn pattern(&self) -> &[(f64, f64)] {
50        match self {
51            Linetype::Solid => &[],
52            Linetype::Dashed => &[(6.0, 3.0)],
53            Linetype::Dotted => &[(2.0, 2.0)],
54            Linetype::DashDot => &[(6.0, 2.0), (2.0, 2.0)],
55            Linetype::LongDash => &[(10.0, 4.0)],
56            Linetype::TwoDash => &[(8.0, 3.0), (3.0, 3.0)],
57        }
58    }
59}
60
61/// Style for drawing points/circles.
62#[derive(Clone, Debug)]
63pub struct PointStyle {
64    pub color: (u8, u8, u8),
65    pub alpha: f64,
66    pub filled: bool,
67    pub shape: PointShape,
68}
69
70impl Default for PointStyle {
71    fn default() -> Self {
72        PointStyle {
73            color: (0, 0, 0),
74            alpha: 1.0,
75            filled: true,
76            shape: PointShape::Circle,
77        }
78    }
79}
80
81/// Style for drawing lines.
82#[derive(Clone, Debug)]
83pub struct LineStyle {
84    pub color: (u8, u8, u8),
85    pub alpha: f64,
86    pub width: f64,
87    pub linetype: Linetype,
88}
89
90impl Default for LineStyle {
91    fn default() -> Self {
92        LineStyle {
93            color: (0, 0, 0),
94            alpha: 1.0,
95            width: 1.0,
96            linetype: Linetype::Solid,
97        }
98    }
99}
100
101/// Style for drawing rectangles/polygons.
102#[derive(Clone, Debug)]
103pub struct RectStyle {
104    pub fill: Option<(u8, u8, u8)>,
105    pub stroke: Option<(u8, u8, u8)>,
106    pub stroke_width: f64,
107    pub alpha: f64,
108    /// Whether to clip this rect to the plot area. Default `true` for data elements.
109    /// Set to `false` for non-data elements (backgrounds, strips, legends).
110    pub clip: bool,
111}
112
113impl Default for RectStyle {
114    fn default() -> Self {
115        RectStyle {
116            fill: Some((128, 128, 128)),
117            stroke: None,
118            stroke_width: 1.0,
119            alpha: 1.0,
120            clip: true,
121        }
122    }
123}
124
125/// Style for drawing text.
126#[derive(Clone, Debug)]
127pub struct TextStyle {
128    pub color: (u8, u8, u8),
129    pub size: f64,
130    pub anchor: TextAnchor,
131    pub angle: f64,
132    /// Font family (e.g., "serif", "monospace"). None defaults to "sans-serif".
133    pub family: Option<String>,
134    /// Font face (R's `element_text(face = ...)`).
135    pub face: FontFace,
136}
137
138/// Font face / weight (R's `element_text(face = ...)`).
139#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
140pub enum FontFace {
141    #[default]
142    Plain,
143    Bold,
144    Italic,
145}
146
147impl Default for TextStyle {
148    fn default() -> Self {
149        TextStyle {
150            color: (50, 50, 50),
151            size: 12.0,
152            anchor: TextAnchor::Middle,
153            angle: 0.0,
154            family: None,
155            face: crate::render::backend::FontFace::Plain,
156        }
157    }
158}
159
160#[derive(Clone, Debug)]
161pub enum TextAnchor {
162    Start,
163    Middle,
164    End,
165}
166
167/// Our rendering abstraction, independent of plotters details.
168pub trait DrawBackend {
169    fn draw_circle(
170        &mut self,
171        center: (f64, f64),
172        radius: f64,
173        style: &PointStyle,
174    ) -> Result<(), RenderError>;
175    fn draw_line(&mut self, points: &[(f64, f64)], style: &LineStyle) -> Result<(), RenderError>;
176    fn draw_rect(
177        &mut self,
178        top_left: (f64, f64),
179        bottom_right: (f64, f64),
180        style: &RectStyle,
181    ) -> Result<(), RenderError>;
182    fn draw_text(
183        &mut self,
184        text: &str,
185        pos: (f64, f64),
186        style: &TextStyle,
187    ) -> Result<(), RenderError>;
188    fn draw_polygon(&mut self, points: &[(f64, f64)], style: &RectStyle)
189        -> Result<(), RenderError>;
190    fn plot_area(&self) -> Rect;
191    fn total_area(&self) -> Rect;
192
193    /// Draw a point with a specific shape. Default delegates to draw_circle for Circle.
194    fn draw_shape(
195        &mut self,
196        center: (f64, f64),
197        radius: f64,
198        style: &PointStyle,
199    ) -> Result<(), RenderError> {
200        match style.shape {
201            PointShape::Circle => self.draw_circle(center, radius, style),
202            _ => {
203                // Default: fall back to circle for unsupported backends
204                self.draw_circle(center, radius, style)
205            }
206        }
207    }
208}