Skip to content

Commit

Permalink
Support group stroke/fill
Browse files Browse the repository at this point in the history
  • Loading branch information
jonmmease committed Jan 29, 2024
1 parent 33aec2a commit 9cb97c4
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 0 deletions.
34 changes: 34 additions & 0 deletions avenger-vega/src/marks/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use crate::marks::mark::{VegaMark, VegaMarkItem};
use avenger::marks::group::{GroupBounds, SceneGroup};
use avenger::marks::mark::SceneMark;
use serde::{Deserialize, Serialize};
use avenger::marks::value::{Gradient};
use crate::marks::values::CssColorOrGradient;

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct VegaGroupItem {
Expand All @@ -11,8 +13,18 @@ pub struct VegaGroupItem {
pub(crate) x: f32,
#[serde(default)]
pub(crate) y: f32,
pub name: Option<String>,
pub width: Option<f32>,
pub height: Option<f32>,
pub fill: Option<CssColorOrGradient>,
pub stroke: Option<CssColorOrGradient>,
pub stroke_width: Option<f32>,
pub corner_radius: Option<f32>,
pub opacity: Option<f32>,
pub fill_opacity: Option<f32>,
pub stroke_opacity: Option<f32>,
pub stroke_offset: Option<f32>,
pub zindex: Option<i32>,
}

impl VegaMarkItem for VegaGroupItem {}
Expand Down Expand Up @@ -63,14 +75,36 @@ impl VegaGroupItem {
};
marks.extend(item_marks);
}

let mut gradients = Vec::<Gradient>::new();
let fill = if let Some(v) = &self.fill {
let opacity = self.fill_opacity.unwrap_or(1.0) * self.opacity.unwrap_or(1.0);
Some(v.to_color_or_grad(opacity, &mut gradients)?)
} else {
None
};
let stroke = if let Some(v) = &self.stroke {
let opacity = self.fill_opacity.unwrap_or(1.0) * self.opacity.unwrap_or(1.0);
Some(v.to_color_or_grad(opacity, &mut gradients)?)
} else {
None
};

Ok(SceneGroup {
name: self.name.clone().unwrap_or_else(|| "group_item".to_string()),
bounds: GroupBounds {
x: self.x,
y: self.y,
width: self.width,
height: self.height,
},
marks,
gradients,
fill,
stroke,
stroke_width: self.stroke_width,
stroke_offset: self.stroke_offset,
corner_radius: self.corner_radius,
})
}
}
7 changes: 7 additions & 0 deletions avenger-vega/src/marks/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,20 @@ impl VegaMarkContainer<VegaSymbolItem> {
line_marks.push(SceneMark::Line(mark));
}
return Ok(SceneMark::Group(SceneGroup {
name: "symbol_line_legend".to_string(),
bounds: GroupBounds {
x: 0.0,
y: 0.0,
width: None,
height: None,
},
marks: line_marks,
gradients: vec![],
fill: None,
stroke: None,
stroke_width: None,
stroke_offset: None,
corner_radius: None,
}));
}

Expand Down
5 changes: 5 additions & 0 deletions avenger-wgpu/src/canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,11 @@ pub trait Canvas {
group: &SceneGroup,
group_bounds: GroupBounds,
) -> Result<(), Sg2dWgpuError> {
// Maybe add rect around group boundary
if let Some(rect) = group.make_rect() {
self.add_rect_mark(&rect, group_bounds)?;
}

// Compute new group bounds
let group_bounds = GroupBounds {
x: group_bounds.x + group.bounds.x,
Expand Down
43 changes: 43 additions & 0 deletions avenger/src/marks/group.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::marks::mark::SceneMark;
use serde::{Deserialize, Serialize};
use crate::marks::rect::RectMark;
use crate::marks::value::{ColorOrGradient, EncodingValue, Gradient};

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct GroupBounds {
Expand All @@ -22,6 +24,47 @@ impl Default for GroupBounds {

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneGroup {
pub name: String,
pub bounds: GroupBounds,
pub marks: Vec<SceneMark>,
pub gradients: Vec<Gradient>,
pub fill: Option<ColorOrGradient>,
pub stroke: Option<ColorOrGradient>,
pub stroke_width: Option<f32>,
pub stroke_offset: Option<f32>,
pub corner_radius: Option<f32>,
}

impl SceneGroup {
pub fn make_rect(&self) -> Option<RectMark> {
if self.fill.is_none() && self.stroke.is_none() {
return None
}
let stroke_width = self.stroke_width.unwrap_or(if self.stroke.is_some() { 1.0 } else { 0.0 });
let stroke_offset = if let Some(stroke_offset) = self.stroke_offset {
stroke_offset
} else {
// From Vega's default stroke offset logic
if (self.stroke.is_some() && stroke_width > 0.5 && stroke_width < 1.5) {
0.5 - (stroke_width - 1.0).abs()
} else {
0.0
}
};
Some(RectMark {
name: format!("rect_{}", self.name),
clip: false,
len: 1,
gradients: self.gradients.clone(),
x: EncodingValue::Scalar { value: self.bounds.x + stroke_offset },
y: EncodingValue::Scalar { value: self.bounds.y + stroke_offset },
width: EncodingValue::Scalar { value: self.bounds.width.unwrap_or(0.0) },
height: EncodingValue::Scalar { value: self.bounds.height.unwrap_or(0.0) },
fill: EncodingValue::Scalar {value: self.fill.clone().unwrap_or(ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]))},
stroke: EncodingValue::Scalar {value: self.stroke.clone().unwrap_or(ColorOrGradient::Color([0.0, 0.0, 0.0, 0.0]))},
stroke_width: EncodingValue::Scalar { value: stroke_width },
corner_radius: EncodingValue::Scalar { value: self.corner_radius.unwrap_or(0.0) },
indices: None,
})
}
}

0 comments on commit 9cb97c4

Please sign in to comment.