diff --git a/Cargo.lock b/Cargo.lock index 6b5db51..de9a81d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2446,7 +2446,7 @@ dependencies = [ [[package]] name = "glyphon" version = "0.3.0" -source = "git+https://github.com/grovesNL/glyphon.git?rev=941309aed230d7110bfec0d4af502ecb4648cf90#941309aed230d7110bfec0d4af502ecb4648cf90" +source = "git+https://github.com/jonmmease/glyphon.git?rev=c468f5dacd4130b27a29b098c4de3f4d5c146209#c468f5dacd4130b27a29b098c4de3f4d5c146209" dependencies = [ "cosmic-text", "etagere", diff --git a/examples/scatter-panning/Cargo.lock b/examples/scatter-panning/Cargo.lock index f9cd148..907a04f 100644 --- a/examples/scatter-panning/Cargo.lock +++ b/examples/scatter-panning/Cargo.lock @@ -724,7 +724,7 @@ dependencies = [ [[package]] name = "glyphon" version = "0.3.0" -source = "git+https://github.com/grovesNL/glyphon.git?rev=941309aed230d7110bfec0d4af502ecb4648cf90#941309aed230d7110bfec0d4af502ecb4648cf90" +source = "git+https://github.com/jonmmease/glyphon.git?rev=0fb93c93da055337590dbf90cf8575374bcdb9ce#0fb93c93da055337590dbf90cf8575374bcdb9ce" dependencies = [ "cosmic-text", "etagere", diff --git a/examples/wgpu-winit/Cargo.lock b/examples/wgpu-winit/Cargo.lock index d68edba..c32a8d3 100644 --- a/examples/wgpu-winit/Cargo.lock +++ b/examples/wgpu-winit/Cargo.lock @@ -724,7 +724,7 @@ dependencies = [ [[package]] name = "glyphon" version = "0.3.0" -source = "git+https://github.com/grovesNL/glyphon.git?rev=941309aed230d7110bfec0d4af502ecb4648cf90#941309aed230d7110bfec0d4af502ecb4648cf90" +source = "git+https://github.com/jonmmease/glyphon.git?rev=0fb93c93da055337590dbf90cf8575374bcdb9ce#0fb93c93da055337590dbf90cf8575374bcdb9ce" dependencies = [ "cosmic-text", "etagere", diff --git a/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.dims.json b/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.dims.json index 25e83d0..119931d 100644 --- a/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.dims.json +++ b/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.dims.json @@ -1,6 +1,6 @@ { - "width": 257, + "width": 272, "height": 102, - "origin_x": 51, + "origin_x": 66, "origin_y": 5 } \ No newline at end of file diff --git a/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.png b/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.png index ce00df1..f2832df 100644 Binary files a/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.png and b/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.png differ diff --git a/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.sg.json b/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.sg.json index 9556005..d9235b6 100644 --- a/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.sg.json +++ b/sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.sg.json @@ -485,6 +485,28 @@ } ], "zindex": 0 + }, + { + "marktype": "text", + "role": "axis-title", + "interactive": false, + "clip": false, + "items": [ + { + "x": -49.9208984375, + "y": 30, + "align": "center", + "baseline": "bottom", + "fill": "#000", + "opacity": 1, + "text": "Activity", + "angle": -90, + "font": "Helvetica", + "fontSize": 11, + "fontWeight": "bold" + } + ], + "zindex": 0 } ], "x": 0.5, diff --git a/sg2d-vega-test-data/vega-scenegraphs/text/text_rotation.dims.json b/sg2d-vega-test-data/vega-scenegraphs/text/text_rotation.dims.json new file mode 100644 index 0000000..0977cec --- /dev/null +++ b/sg2d-vega-test-data/vega-scenegraphs/text/text_rotation.dims.json @@ -0,0 +1,6 @@ +{ + "width": 210, + "height": 210, + "origin_x": 5, + "origin_y": 5 +} \ No newline at end of file diff --git a/sg2d-vega-test-data/vega-scenegraphs/text/text_rotation.png b/sg2d-vega-test-data/vega-scenegraphs/text/text_rotation.png new file mode 100644 index 0000000..c4e64e0 Binary files /dev/null and b/sg2d-vega-test-data/vega-scenegraphs/text/text_rotation.png differ diff --git a/sg2d-vega-test-data/vega-scenegraphs/text/text_rotation.sg.json b/sg2d-vega-test-data/vega-scenegraphs/text/text_rotation.sg.json new file mode 100644 index 0000000..32552d2 --- /dev/null +++ b/sg2d-vega-test-data/vega-scenegraphs/text/text_rotation.sg.json @@ -0,0 +1,112 @@ +{ + "marktype": "group", + "name": "root", + "role": "frame", + "interactive": true, + "clip": false, + "items": [ + { + "items": [ + { + "marktype": "symbol", + "name": "points", + "role": "mark", + "interactive": true, + "clip": false, + "items": [ + { + "x": 40, + "y": 15, + "fill": "orange", + "size": 30, + "shape": "triangle-up", + "angle": 0 + }, + { + "x": 20, + "y": 70, + "fill": "blue", + "size": 30, + "shape": "triangle-up", + "angle": 30 + }, + { + "x": 80, + "y": 160, + "fill": "green", + "size": 30, + "shape": "triangle-up", + "angle": -90 + }, + { + "x": 120, + "y": 160, + "fill": "purple", + "size": 30, + "shape": "triangle-up", + "angle": -27 + } + ], + "zindex": 0 + }, + { + "marktype": "text", + "name": "text", + "role": "mark", + "interactive": true, + "clip": false, + "items": [ + { + "x": 40, + "y": 15, + "baseline": "top", + "fill": "orange", + "text": "hello", + "angle": 0, + "font": "Helvetica", + "fontSize": 20 + }, + { + "x": 20, + "y": 70, + "baseline": "middle", + "fill": "blue", + "text": "hello", + "angle": 30, + "font": "Helvetica", + "fontSize": 20 + }, + { + "x": 80, + "y": 160, + "baseline": "bottom", + "fill": "green", + "text": "hello", + "angle": -90, + "font": "Helvetica", + "fontSize": 20 + }, + { + "x": 120, + "y": 160, + "baseline": "alphabetic", + "fill": "purple", + "text": "hello", + "angle": -27, + "font": "Helvetica", + "fontSize": 20 + } + ], + "zindex": 0 + } + ], + "x": 0, + "y": 0, + "width": 200, + "height": 200, + "fill": "transparent", + "stroke": "transparent" + } + ], + "zindex": 0 +} \ No newline at end of file diff --git a/sg2d-vega-test-data/vega-specs/text/bar_axis_labels.vg.json b/sg2d-vega-test-data/vega-specs/text/bar_axis_labels.vg.json index e3cf559..e70ed43 100644 --- a/sg2d-vega-test-data/vega-specs/text/bar_axis_labels.vg.json +++ b/sg2d-vega-test-data/vega-specs/text/bar_axis_labels.vg.json @@ -127,9 +127,10 @@ "scale": "y", "orient": "left", "grid": false, + "title": "Activity", + "zindex": 0, "labelFont": "Helvetica", - "titleFont": "Helvetica", - "zindex": 0 + "titleFont": "Helvetica" } ] } diff --git a/sg2d-vega-test-data/vega-specs/text/text_rotation.vg.json b/sg2d-vega-test-data/vega-specs/text/text_rotation.vg.json new file mode 100644 index 0000000..62b81f3 --- /dev/null +++ b/sg2d-vega-test-data/vega-specs/text/text_rotation.vg.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://vega.github.io/schema/vega/v5.json", + "description": "A scatterplot showing horsepower and miles per gallons for various cars.", + "background": "white", + "padding": 5, + "width": 200, + "height": 200, + "style": "cell", + "config": {"style": {"cell": {"stroke": "transparent"}}}, + "data": [{ + "name": "source_0", + "values": [ + {"x": 40, "y": 15, "fill": "orange", "angle": 0, "baseline": "top"}, + {"x": 20, "y": 70, "fill": "blue", "angle": 30, "baseline": "middle"}, + {"x": 80, "y": 160, "fill": "green", "angle": -90, "baseline": "bottom"}, + {"x": 120, "y": 160, "fill": "purple", "angle": -27, "baseline": "alphabetic"} + ] + }], + "marks": [ + { + "name": "points", + "type": "symbol", + "from": {"data": "source_0"}, + "encode": { + "update": { + "shape": {"value": "triangle-up"}, + "size": {"value": 30}, + "fill": {"field": "fill"}, + "x": {"field": "x" }, + "y": {"field": "y"}, + "angle": {"field": "angle"} + } + } + }, + { + "name": "text", + "type": "text", + "from": {"data": "source_0"}, + "encode": { + "update": { + "text": {"value": "hello"}, + "font": {"value": "Helvetica"}, + "fontSize": {"value": 20}, + "fill": {"field": "fill"}, + "x": {"field": "x" }, + "y": {"field": "y"}, + "angle": {"field": "angle"}, + "baseline": {"field": "baseline"} + } + } + } + ] +} diff --git a/sg2d-wgpu/Cargo.toml b/sg2d-wgpu/Cargo.toml index daec904..19c9e14 100644 --- a/sg2d-wgpu/Cargo.toml +++ b/sg2d-wgpu/Cargo.toml @@ -21,7 +21,9 @@ cgmath = "0.18.0" itertools = "0.12.0" image = "0.24.7" futures-intrusive = "^0.5" -glyphon = { git = "https://github.com/grovesNL/glyphon.git", rev="941309aed230d7110bfec0d4af502ecb4648cf90" } + +# glyphon branch that includes text rotation support: https://github.com/jonmmease/glyphon/pull/1 +glyphon = { git = "https://github.com/jonmmease/glyphon.git", rev="c468f5dacd4130b27a29b098c4de3f4d5c146209" } lyon = { workspace = true } [dev-dependencies] diff --git a/sg2d-wgpu/src/marks/text.rs b/sg2d-wgpu/src/marks/text.rs index b407503..e61392a 100644 --- a/sg2d-wgpu/src/marks/text.rs +++ b/sg2d-wgpu/src/marks/text.rs @@ -187,7 +187,7 @@ impl TextMarkRenderer { .iter() .zip(&self.instances) .map(|(buffer, instance)| { - let (width, height) = measure(buffer); + let (width, line_y, height) = measure(buffer); let scaled_x = instance.position[0] * self.uniform.scale; let scaled_y = instance.position[1] * self.uniform.scale; let left = match instance.align { @@ -197,8 +197,7 @@ impl TextMarkRenderer { }; let mut top = match instance.baseline { - TextBaselineSpec::Alphabetic => scaled_y - height, - + TextBaselineSpec::Alphabetic => scaled_y - line_y, TextBaselineSpec::Top => scaled_y, TextBaselineSpec::Middle => scaled_y - height * 0.5, TextBaselineSpec::Bottom => scaled_y - height, @@ -225,6 +224,8 @@ impl TextMarkRenderer { (instance.color[1] * 255.0) as u8, (instance.color[2] * 255.0) as u8, ), + angle: instance.angle, + rotation_origin: Some([scaled_x, scaled_y]), } }) .collect::>(); @@ -270,11 +271,20 @@ impl TextMarkRenderer { } } -pub fn measure(buffer: &Buffer) -> (f32, f32) { - let (width, total_lines) = buffer - .layout_runs() - .fold((0.0, 0usize), |(width, total_lines), run| { - (run.line_w.max(width), total_lines + 1) - }); - (width, (total_lines as f32 * buffer.metrics().line_height)) +pub fn measure(buffer: &Buffer) -> (f32, f32, f32) { + let (width, line_y, total_lines) = + buffer + .layout_runs() + .fold((0.0, 0.0, 0usize), |(width, line_y, total_lines), run| { + ( + run.line_w.max(width), + run.line_y.max(line_y), + total_lines + 1, + ) + }); + ( + width, + line_y, + (total_lines as f32 * buffer.metrics().line_height), + ) } diff --git a/sg2d-wgpu/tests/test_image_baselines.rs b/sg2d-wgpu/tests/test_image_baselines.rs index b85dec8..459d308 100644 --- a/sg2d-wgpu/tests/test_image_baselines.rs +++ b/sg2d-wgpu/tests/test_image_baselines.rs @@ -42,7 +42,8 @@ mod test_image_baselines { case("rule", "wide_rule_axes", 0.0001), case("rule", "wide_transparent_caps", 0.0001), case("rule", "dashed_rules", 0.0001), - case("text", "bar_axis_labels", 0.01) + case("text", "bar_axis_labels", 0.01), + case("text", "text_rotation", 0.015) )] fn test_image_baseline(category: &str, spec_name: &str, tolerance: f64) { let specs_dir = format!(