Skip to content

Commit

Permalink
Push group clipping down, support rounded rectangle example
Browse files Browse the repository at this point in the history
  • Loading branch information
jonmmease committed Mar 2, 2024
1 parent 5ecc19c commit 1f2b095
Show file tree
Hide file tree
Showing 18 changed files with 2,158 additions and 41 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1,903 changes: 1,903 additions & 0 deletions avenger-vega-test-data/vega-scenegraphs/clip/bar_rounded.sg.json

Large diffs are not rendered by default.

179 changes: 179 additions & 0 deletions avenger-vega-test-data/vega-specs/clip/bar_rounded.vg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"background": "white",
"padding": 5,
"height": 200,
"style": "cell",
"data": [
{
"name": "source_0",
"url": "data/seattle-weather.csv",
"format": {"type": "csv", "parse": {"date": "date"}},
"transform": [
{
"field": "date",
"type": "timeunit",
"units": ["month"],
"as": ["month_date", "month_date_end"]
},
{
"type": "aggregate",
"groupby": ["month_date", "weather"],
"ops": ["count"],
"fields": [null],
"as": ["__count"]
},
{
"type": "stack",
"groupby": ["month_date"],
"field": "__count",
"sort": {"field": ["weather"], "order": ["descending"]},
"as": ["__count_start", "__count_end"],
"offset": "zero"
}
]
}
],
"signals": [
{"name": "x_step", "value": 20},
{
"name": "width",
"update": "bandspace(domain('x').length, 0.1, 0.05) * x_step"
}
],
"marks": [
{
"type": "group",
"from": {
"facet": {
"data": "source_0",
"name": "stack_group_main",
"groupby": ["month_date", "month_date_end"],
"aggregate": {
"fields": [
"__count_start",
"__count_start",
"__count_end",
"__count_end"
],
"ops": ["min", "max", "min", "max"]
}
}
},
"encode": {
"update": {
"x": {"scale": "x", "field": "month_date"},
"width": {"signal": "max(0.25, bandwidth('x'))"},
"y": {
"signal": "min(scale('y',datum[\"min___count_start\"]),scale('y',datum[\"max___count_start\"]),scale('y',datum[\"min___count_end\"]),scale('y',datum[\"max___count_end\"]))"
},
"y2": {
"signal": "max(scale('y',datum[\"min___count_start\"]),scale('y',datum[\"max___count_start\"]),scale('y',datum[\"min___count_end\"]),scale('y',datum[\"max___count_end\"]))"
},
"clip": {"value": true},
"cornerRadiusTopLeft": {"value": 10},
"cornerRadiusTopRight": {"value": 5}
}
},
"marks": [
{
"type": "group",
"encode": {
"update": {
"y": {"field": {"group": "y"}, "mult": -1},
"width": {"field": {"group": "width"}}
}
},
"marks": [
{
"name": "marks",
"type": "rect",
"style": ["bar"],
"from": {"data": "stack_group_main"},
"encode": {
"update": {
"fill": {"scale": "color", "field": "weather"},
"ariaRoleDescription": {"value": "bar"},
"description": {
"signal": "\"date (month): \" + (timeFormat(datum[\"month_date\"], timeUnitSpecifier([\"month\"], {\"year-month\":\"%b %Y \",\"year-month-date\":\"%b %d, %Y \"}))) + \"; Count of Records: \" + (format(datum[\"__count\"], \"\")) + \"; weather: \" + (isValid(datum[\"weather\"]) ? datum[\"weather\"] : \"\"+datum[\"weather\"])"
},
"width": {"field": {"group": "width"}},
"y": {"scale": "y", "field": "__count_end"},
"y2": {"scale": "y", "field": "__count_start"}
}
}
}
]
}
]
}
],
"scales": [
{
"name": "x",
"type": "band",
"domain": {"data": "source_0", "field": "month_date", "sort": true},
"range": {"step": {"signal": "x_step"}},
"paddingInner": 0.1,
"paddingOuter": 0.05
},
{
"name": "y",
"type": "linear",
"domain": {
"data": "source_0",
"fields": ["__count_start", "__count_end"]
},
"range": [{"signal": "height"}, 0],
"nice": true,
"zero": true
},
{
"name": "color",
"type": "ordinal",
"domain": {"data": "source_0", "field": "weather", "sort": true},
"range": "category"
}
],
"axes": [
{
"scale": "y",
"orient": "left",
"gridScale": "x",
"grid": true,
"tickCount": {"signal": "ceil(height/40)"},
"domain": false,
"labels": false,
"aria": false,
"maxExtent": 0,
"minExtent": 0,
"ticks": false,
"zindex": 0
},
{
"scale": "x",
"orient": "bottom",
"grid": false,
"title": "date (month)",
"format": {
"signal": "timeUnitSpecifier([\"month\"], {\"year-month\":\"%b %Y \",\"year-month-date\":\"%b %d, %Y \"})"
},
"formatType": "time",
"labelOverlap": true,
"tickMinStep": {
"signal": "datetime(2001, 1, 1, 0, 0, 0, 0) - datetime(2001, 0, 1, 0, 0, 0, 0)"
},
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"grid": false,
"title": "Count of Records",
"labelOverlap": true,
"tickCount": {"signal": "ceil(height/40)"},
"zindex": 0
}
],
"legends": [{"fill": "color", "symbolType": "square", "title": "weather"}]
}
4 changes: 2 additions & 2 deletions avenger-vega/src/marks/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ pub struct VegaArcItem {
impl VegaMarkItem for VegaArcItem {}

impl VegaMarkContainer<VegaArcItem> {
pub fn to_scene_graph(&self) -> Result<SceneMark, AvengerVegaError> {
pub fn to_scene_graph(&self, force_clip: bool) -> Result<SceneMark, AvengerVegaError> {
// Init mark with scalar defaults
let mut mark = ArcMark {
clip: self.clip,
clip: self.clip || force_clip,
zindex: self.zindex,
..Default::default()
};
Expand Down
4 changes: 2 additions & 2 deletions avenger-vega/src/marks/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct VegaAreaItem {
impl VegaMarkItem for VegaAreaItem {}

impl VegaMarkContainer<VegaAreaItem> {
pub fn to_scene_graph(&self) -> Result<SceneMark, AvengerVegaError> {
pub fn to_scene_graph(&self, force_clip: bool) -> Result<SceneMark, AvengerVegaError> {
// Get shape of first item and use that for all items for now
let first = self.items.first();
let stroke_cap = first.and_then(|item| item.stroke_cap).unwrap_or_default();
Expand Down Expand Up @@ -61,7 +61,7 @@ impl VegaMarkContainer<VegaAreaItem> {
}

let mut mark = AreaMark {
clip: self.clip,
clip: self.clip || force_clip,
zindex: self.zindex,
orientation,
fill,
Expand Down
57 changes: 42 additions & 15 deletions avenger-vega/src/marks/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize};
#[serde(rename_all = "camelCase")]
pub struct VegaGroupItem {
pub items: Vec<VegaMark>,
pub clip: Option<bool>,
pub x: Option<f32>,
pub y: Option<f32>,
pub name: Option<String>,
Expand All @@ -22,6 +23,10 @@ pub struct VegaGroupItem {
pub stroke: Option<CssColorOrGradient>,
pub stroke_width: Option<f32>,
pub corner_radius: Option<f32>,
pub corner_radius_top_left: Option<f32>,
pub corner_radius_top_right: Option<f32>,
pub corner_radius_bottom_left: Option<f32>,
pub corner_radius_bottom_right: Option<f32>,
pub opacity: Option<f32>,
pub fill_opacity: Option<f32>,
pub stroke_opacity: Option<f32>,
Expand All @@ -32,49 +37,50 @@ pub struct VegaGroupItem {
impl VegaMarkItem for VegaGroupItem {}

impl VegaMarkContainer<VegaGroupItem> {
pub fn to_scene_graph(&self) -> Result<Vec<SceneGroup>, AvengerVegaError> {
pub fn to_scene_graph(&self, force_clip: bool) -> Result<Vec<SceneGroup>, AvengerVegaError> {
let mut groups: Vec<SceneGroup> = Vec::new();
for group_item in &self.items {
let should_clip = group_item.clip.unwrap_or(false) || force_clip;
let mut marks: Vec<SceneMark> = Vec::new();
for item in &group_item.items {
let item_marks: Vec<SceneMark> = match item {
VegaMark::Group(mark) => mark
.to_scene_graph()?
.to_scene_graph(should_clip)?
.into_iter()
.map(SceneMark::Group)
.collect(),
VegaMark::Rect(mark) => {
vec![mark.to_scene_graph()?]
vec![mark.to_scene_graph(should_clip)?]
}
VegaMark::Rule(mark) => {
vec![mark.to_scene_graph()?]
vec![mark.to_scene_graph(should_clip)?]
}
VegaMark::Symbol(mark) => {
vec![mark.to_scene_graph()?]
vec![mark.to_scene_graph(should_clip)?]
}
VegaMark::Text(mark) => {
vec![mark.to_scene_graph()?]
vec![mark.to_scene_graph(should_clip)?]
}
VegaMark::Arc(mark) => {
vec![mark.to_scene_graph()?]
vec![mark.to_scene_graph(should_clip)?]
}
VegaMark::Path(mark) => {
vec![mark.to_scene_graph()?]
vec![mark.to_scene_graph(should_clip)?]
}
VegaMark::Shape(mark) => {
vec![mark.to_scene_graph()?]
vec![mark.to_scene_graph(should_clip)?]
}
VegaMark::Line(mark) => {
vec![mark.to_scene_graph()?]
vec![mark.to_scene_graph(should_clip)?]
}
VegaMark::Area(mark) => {
vec![mark.to_scene_graph()?]
vec![mark.to_scene_graph(should_clip)?]
}
VegaMark::Trail(mark) => {
vec![mark.to_scene_graph()?]
vec![mark.to_scene_graph(should_clip)?]
}
VegaMark::Image(mark) => {
vec![mark.to_scene_graph()?]
vec![mark.to_scene_graph(should_clip)?]
}
};
marks.extend(item_marks);
Expand All @@ -97,12 +103,33 @@ impl VegaMarkContainer<VegaGroupItem> {
};

let clip = if let (Some(width), Some(height)) = (group_item.width, group_item.height) {
if let Some(corner_radius) = group_item.corner_radius {
let corner_radius = group_item.corner_radius.unwrap_or(0.0);
let corner_radius_top_left =
group_item.corner_radius_top_left.unwrap_or(corner_radius);
let corner_radius_top_right =
group_item.corner_radius_top_right.unwrap_or(corner_radius);
let corner_radius_bottom_left = group_item
.corner_radius_bottom_left
.unwrap_or(corner_radius);
let corner_radius_bottom_right = group_item
.corner_radius_bottom_right
.unwrap_or(corner_radius);

if corner_radius_top_left > 0.0
|| corner_radius_top_right > 0.0
|| corner_radius_bottom_left > 0.0
|| corner_radius_bottom_right > 0.0
{
// Rounded rectange path
let mut builder = lyon_path::Path::builder();
builder.add_rounded_rectangle(
&Box2D::new(Point2D::new(0.0, 0.0), Point2D::new(width, height)),
&BorderRadii::new(corner_radius),
&BorderRadii {
top_left: corner_radius_top_left,
top_right: corner_radius_top_right,
bottom_left: corner_radius_bottom_left,
bottom_right: corner_radius_bottom_right,
},
Winding::Positive,
);
Clip::Path(builder.build())
Expand Down
4 changes: 2 additions & 2 deletions avenger-vega/src/marks/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn default_true() -> bool {
impl VegaMarkItem for VegaImageItem {}

impl VegaMarkContainer<VegaImageItem> {
pub fn to_scene_graph(&self) -> Result<SceneMark, AvengerVegaError> {
pub fn to_scene_graph(&self, force_clip: bool) -> Result<SceneMark, AvengerVegaError> {
let name = self
.name
.clone()
Expand Down Expand Up @@ -96,7 +96,7 @@ impl VegaMarkContainer<VegaImageItem> {

Ok(SceneMark::Image(Box::new(ImageMark {
name,
clip: self.clip,
clip: self.clip || force_clip,
len: self.items.len() as u32,
aspect,
smooth,
Expand Down
4 changes: 2 additions & 2 deletions avenger-vega/src/marks/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub struct VegaLineItem {
impl VegaMarkItem for VegaLineItem {}

impl VegaMarkContainer<VegaLineItem> {
pub fn to_scene_graph(&self) -> Result<SceneMark, AvengerVegaError> {
pub fn to_scene_graph(&self, force_clip: bool) -> Result<SceneMark, AvengerVegaError> {
// Get shape of first item and use that for all items for now
let first = self.items.first();
let stroke_width = first.and_then(|item| item.stroke_width).unwrap_or(1.0);
Expand All @@ -47,7 +47,7 @@ impl VegaMarkContainer<VegaLineItem> {
}

let mut mark = LineMark {
clip: self.clip,
clip: self.clip || force_clip,
zindex: self.zindex,
stroke,
stroke_width,
Expand Down
4 changes: 2 additions & 2 deletions avenger-vega/src/marks/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub struct VegaPathItem {
impl VegaMarkItem for VegaPathItem {}

impl VegaMarkContainer<VegaPathItem> {
pub fn to_scene_graph(&self) -> Result<SceneMark, AvengerVegaError> {
pub fn to_scene_graph(&self, force_clip: bool) -> Result<SceneMark, AvengerVegaError> {
// Get shape of first item and use that for all items for now
let first = self.items.first();
let first_has_stroke = first.map(|item| item.stroke.is_some()).unwrap_or(false);
Expand All @@ -49,7 +49,7 @@ impl VegaMarkContainer<VegaPathItem> {

// Init mark with scalar defaults
let mut mark = PathMark {
clip: self.clip,
clip: self.clip || force_clip,
zindex: self.zindex,
stroke_cap: first_cap,
stroke_join: first_join,
Expand Down
4 changes: 2 additions & 2 deletions avenger-vega/src/marks/rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ pub struct VegaRectItem {
impl VegaMarkItem for VegaRectItem {}

impl VegaMarkContainer<VegaRectItem> {
pub fn to_scene_graph(&self) -> Result<SceneMark, AvengerVegaError> {
pub fn to_scene_graph(&self, force_clip: bool) -> Result<SceneMark, AvengerVegaError> {
let mut mark = RectMark {
clip: self.clip,
clip: self.clip || force_clip,
zindex: self.zindex,
..Default::default()
};
Expand Down
Loading

0 comments on commit 1f2b095

Please sign in to comment.