plotters 0.1.1

Anoter Plotting Library in Rust
Documentation
use svg::node::element::{Circle, Rectangle, Polyline, Text, Line};
use svg::Document;

use crate::style::{Color, FontDesc};
use crate::drawing::backend::{DrawingErrorKind, DrawingBackend, BackendCoord};

use std::io::Error;

fn make_svg_color<C:Color>(color:&C) -> String {
    let (r,g,b) = color.rgb();
    let a   = color.alpha();
    return format!("rgba({},{},{},{})", r,g,b,a);
}

pub struct SVGBackend<'a> {
    path: &'a str,
    size: (u32,u32),
    document: Option<Document>,
}

impl <'a> SVGBackend<'a> {
    fn update_document<F:FnOnce(Document) -> Document>(&mut self, op:F) {
        let mut temp = None;
        std::mem::swap(&mut temp, &mut self.document);
        self.document = Some(op(temp.unwrap()));
    }

    pub fn new(path: &'a str, size:(u32,u32)) -> Self {
        return Self {
            path,
            size,
            document: Some(Document::new().set("view_box", (0,0,size.0,size.1)))
        };
    }
}

impl<'a> DrawingBackend for SVGBackend<'a> {
    type ErrorType = Error;
    
    fn get_size(&self) -> (u32, u32) {
        return self.size;
    }

    fn open(&mut self) -> Result<(), DrawingErrorKind<Error>> {
        Ok(())
    }

    fn close(&mut self) -> Result<(), DrawingErrorKind<Error>> {
        return svg::save(self.path, self.document.as_ref().unwrap()).map_err(|x| DrawingErrorKind::DrawingError(x));
    }

    fn draw_pixel<C: Color>(
        &mut self,
        point: BackendCoord,
        color: &C,
    ) -> Result<(), DrawingErrorKind<Error>> {
        let node = Rectangle::new()
            .set("x", point.0)
            .set("y", point.1)
            .set("width", 1)
            .set("height", 1)
            .set("stroke", "none")
            .set("fill", make_svg_color(color));
        self.update_document(|d| d.add(node));
        return Ok(());
    }
    
    fn draw_line<C: Color>(
        &mut self,
        from: BackendCoord,
        to: BackendCoord,
        color: &C,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
         let node = Line::new()
            .set("x1", from.0)
            .set("y1", from.1)
            .set("x2", to.0)
            .set("y2", to.1)
            .set("stroke", make_svg_color(color));
         self.update_document(|d| d.add(node));
         return Ok(());
    }

    fn draw_rect<C: Color>(
        &mut self,
        upper_left: BackendCoord,
        bottom_right: BackendCoord,
        color: &C,
        fill: bool,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
         let mut node = Rectangle::new()
            .set("x", upper_left.0)
            .set("y", upper_left.1)
            .set("width", bottom_right.0 - upper_left.0)
            .set("height", bottom_right.1 - upper_left.1);

        if !fill {
            node = node.set("stroke", make_svg_color(color))
                .set("fill", "none");
        } else {
            node = node.set("fill", make_svg_color(color))
                .set("stroke", "none");
        }

        self.update_document(|d| d.add(node));
        return Ok(());
    }

    fn draw_path<C: Color, I: IntoIterator<Item = BackendCoord>>(
        &mut self,
        path: I,
        color: &C,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        let node = Polyline::new()
            .set("fill", "none")
            .set("stroke", make_svg_color(color))
            .set("points", path.into_iter().fold(String::new(), |mut s, (x,y)| {
                s.push_str(&format!("{},{} ", x,y));
                return s;
            }));
        self.update_document(|d| d.add(node));
        return Ok(());
    }

    fn draw_circle<C: Color>(
        &mut self,
        center: BackendCoord,
        radius: u32,
        color: &C,
        fill: bool,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        let mut node = Circle::new()
            .set("cx", center.0)
            .set("cy", center.1)
            .set("r", radius);
        
        if !fill {
            node = node.set("stroke", make_svg_color(color))
                .set("fill", "none");
        } else {
            node = node.set("fill", make_svg_color(color))
                .set("stroke", "none");
        }

        self.update_document(|d| d.add(node));
        return Ok(());

    }
    fn draw_text<'b, C: Color>(
        &mut self,
        text: &str,
        font: &FontDesc<'b>,
        pos: BackendCoord,
        color: &C,
    ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
        let context = svg::node::Text::new(text);
        let node = Text::new()
            .set("x", pos.0)
            .set("y", pos.1 as f64 + font.get_size())
            .set("font-famliy", font.get_name())
            .set("font-size", font.get_size() * 0.8)
            .set("fill", make_svg_color(color))
            .add(context);
        self.update_document(|d| d.add(node));
        return Ok(());

    }
}