This repository has no description
1use crate::{graphics::objects::ObjectSizes, ColorMapping};
2use anyhow::Result;
3use itertools::Itertools;
4use std::collections::HashMap;
5
6/// Struct can be rendered as a SVG element
7pub trait SVGRenderable {
8 fn render_to_svg(
9 &self,
10 colormap: ColorMapping,
11 cell_size: usize,
12 object_sizes: ObjectSizes,
13 id: &str,
14 ) -> Result<svg::node::element::Element>;
15}
16
17/// Struct can be rendered as attributes of a SVG element
18pub trait SVGAttributesRenderable {
19 /// When merging multiple SVGAttributesRenderable, this string is used to join multiple values for the same key
20 const MULTIPLE_VALUES_JOIN_BY: &'static str = ", ";
21
22 fn render_to_svg_attributes(
23 &self,
24 colormap: ColorMapping,
25 cell_size: usize,
26 object_sizes: ObjectSizes,
27 id: &str,
28 ) -> Result<HashMap<String, String>>;
29}
30
31/// Struct can be rendered as a CSS ruleset (e.g. no selectors)
32pub trait CSSRenderable {
33 fn render_to_css_filled(&self, colormap: &ColorMapping) -> String;
34 fn render_to_css_stroked(&self, colormap: &ColorMapping) -> String;
35 fn render_to_css(
36 &self,
37 colormap: &ColorMapping,
38 fill_as_stroke_color: bool,
39 ) -> String {
40 if fill_as_stroke_color {
41 self.render_to_css_stroked(colormap)
42 } else {
43 self.render_to_css_filled(colormap)
44 }
45 }
46}
47
48impl<T: CSSRenderable, V: Clone + IntoIterator<Item = T>> CSSRenderable for V {
49 fn render_to_css_filled(&self, colormap: &ColorMapping) -> String {
50 self.clone()
51 .into_iter()
52 .map(|v| v.render_to_css_filled(colormap))
53 .join("\n")
54 }
55
56 fn render_to_css_stroked(&self, colormap: &ColorMapping) -> String {
57 self.clone()
58 .into_iter()
59 .map(|v| v.render_to_css_stroked(colormap))
60 .join("\n")
61 }
62}
63
64// We get the Option<T> implementation for free since Option<T> implements IntoIterator, and it works:
65// None => empty iterator => empty hashmap,
66// Some(T) => iterator with one element => one hashmap, no merging.
67// I love Rust <3.
68
69impl<T, V> SVGAttributesRenderable for V
70where
71 T: SVGAttributesRenderable,
72 V: Clone + IntoIterator<Item = T>,
73{
74 fn render_to_svg_attributes(
75 &self,
76 colormap: ColorMapping,
77 cell_size: usize,
78 object_sizes: ObjectSizes,
79 id: &str,
80 ) -> Result<HashMap<String, String>> {
81 let mut attrs = HashMap::<String, String>::new();
82 for attrmap in self.clone().into_iter().map(|v| {
83 v.render_to_svg_attributes(
84 colormap.clone(),
85 cell_size,
86 object_sizes,
87 id,
88 )
89 .unwrap()
90 }) {
91 for (key, value) in attrmap {
92 if attrs.contains_key(&key) {
93 attrs.insert(
94 key.clone(),
95 format!(
96 "{}{}{}",
97 attrs[&key],
98 T::MULTIPLE_VALUES_JOIN_BY,
99 value
100 ),
101 );
102 } else {
103 attrs.insert(key, value);
104 }
105 }
106 }
107 Ok(attrs)
108 }
109}