This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1use crate::{Angle, Color, ColorMapping, rendering::svg}; 2 3#[derive(Debug, Clone, Copy)] 4pub enum Fill { 5 Solid(Color), 6 Translucent(Color, f32), 7 /// Hatches(color, angle, thickness_ratio, spacing) 8 Hatches(Color, Angle, f32, f32), 9 /// Dotted(color, diameter, spacing) 10 Dotted(Color, f32, f32), 11} 12 13impl Color { 14 pub fn solid(self) -> Fill { 15 Fill::Solid(self) 16 } 17 18 pub fn translucent(self, opacity: f32) -> Fill { 19 Fill::Translucent(self, opacity) 20 } 21 22 pub fn hatches(self, angle: Angle, thickness: f32, spacing: f32) -> Fill { 23 Fill::Hatches(self, angle, thickness, spacing) 24 } 25 26 pub fn dotted(self, diameter: f32, spacing: f32) -> Fill { 27 Fill::Dotted(self, diameter, spacing) 28 } 29} 30 31// Operations that can be applied on fills. 32pub trait FillOperations { 33 fn opacify(&self, opacity: f32) -> Self; 34} 35 36impl FillOperations for Fill { 37 fn opacify(&self, opacity: f32) -> Self { 38 match self { 39 Fill::Solid(color) => Fill::Translucent(*color, opacity), 40 Fill::Translucent(color, _) => Fill::Translucent(*color, opacity), 41 _ => *self, 42 } 43 } 44} 45 46impl FillOperations for Option<Fill> { 47 fn opacify(&self, opacity: f32) -> Self { 48 self.map(|fill| fill.opacify(opacity)) 49 } 50} 51 52impl Fill { 53 pub fn bottom_up_hatches(color: Color, thickness: f32, spacing: f32) -> Self { 54 Fill::Hatches(color, Angle(45.0), thickness, spacing) 55 } 56 57 pub fn pattern_id(&self) -> String { 58 if let Fill::Hatches(color, angle, thickness, spacing) = self { 59 return format!( 60 "pattern-hatched-{}-{}-{}-{}", 61 angle, 62 color.name(), 63 thickness, 64 spacing 65 ); 66 } 67 if let Fill::Dotted(color, diameter, spacing) = self { 68 return format!( 69 "pattern-dotted-{}-{}-{}", 70 color.name(), 71 diameter, 72 spacing 73 ); 74 } 75 String::from("") 76 } 77 78 pub fn pattern_definition( 79 &self, 80 colormapping: &ColorMapping, 81 ) -> Option<svg::Node> { 82 match self { 83 Fill::Hatches(color, angle, size, thickness_ratio) => { 84 let thickness = size * (2.0 * thickness_ratio); 85 86 let pattern = svg::tag("pattern") 87 .attr("id", self.pattern_id()) 88 .attr("patternUnits", "userSpaceOnUse") 89 .attr("height", size * 2.0) 90 .attr("width", size * 2.0) 91 .attr("viewBox", format!("0,0,{},{}", size, size)) 92 .attr( 93 "patternTransform", 94 format!("rotate({})", (*angle - Angle(45.0)).degrees()), 95 ) 96 // https://stackoverflow.com/a/55104220/9943464 97 .wrapping(vec![ 98 svg::tag("polygon").fill(*color, colormapping).attr( 99 "points", 100 format!( 101 "0,0 {},0 0,{}", 102 thickness / 2.0, 103 thickness / 2.0 104 ), 105 ), 106 svg::tag("polygon").fill(*color, colormapping).attr( 107 "points", 108 format!( 109 "0,{} {},0 {},{} {},{}", 110 size, 111 size, 112 size, 113 thickness / 2.0, 114 thickness / 2.0, 115 size, 116 ), 117 ), 118 ]) 119 .node(); 120 121 Some(pattern) 122 } 123 Fill::Dotted(color, diameter, spacing) => { 124 let box_size = diameter + 2.0 * spacing; 125 let pattern = svg::tag("pattern") 126 .attr("id", self.pattern_id()) 127 .attr("patternUnits", "userSpaceOnUse") 128 .attr("height", box_size) 129 .attr("width", box_size) 130 .attr("viewBox", format!("0,0,{},{}", box_size, box_size)) 131 .wrapping(vec![ 132 svg::tag("circle") 133 .fill(*color, colormapping) 134 .attr("cx", box_size / 2.0) 135 .attr("cy", box_size / 2.0) 136 .attr("r", diameter / 2.0), 137 ]) 138 .node(); 139 140 Some(pattern) 141 } 142 _ => None, 143 } 144 } 145}