For drawing custom graphics, azul has a high-performance 2D vector API. It alsoallows you to load and draw SVG files (with the exceptions of gradients: gradientsin SVG files are not yet supported). But azul itself does not know about SVG shapesat all - so how the SVG widget implemented?
The solution is to draw the SVG to an OpenGL texture and hand that to azul. Thisway, the SVG drawing component could even be implemented in an external crate, ifyou really wanted to. This mechanism also allows for completely custom drawing(let's say: a game, a 3D viewer, etc.) to be drawn.
Necessary features
SVG rendering has a number of dependencies that are not enabled by default, to saveon compile time in simple cases (i.e. by default the SVG module is disabled, sothat a Hello-World doesn't need to compile those unnecessary dependencies):
- [dependencies.azul]
- git = "https://github.com/maps4print/azul"
- rev = "..."
- features = ["svg", "svg_parsing"]
You only need to enable the svg_parsing
feature if you want to parse SVG files.For building the documentation, you'll likely want to run cargo doc —all-features
.You can import the SVG module using use azul::widgets::svg::*;
.
Getting started
The SVG component currently uses the resvg
parser, usvg
simplification and thelyon
triangulation libraries). Of course you can also add custom shapes(bezier curves, circles, lines, whatever) programmatically, without going throughthe SVG parser:
- use azul::prelude::*;
- use azul::widgets::svg::*;
- const TEST_SVG: &str = include_str!("tiger.svg");
- impl Layout for Model {
- fn layout(&self, _info: LayoutInfo<Self>) -> Dom<Self> {
- if let Some((svg_cache, svg_layers)) = self.svg {
- Svg::with_layers(svg_layers).dom(&info.window, &svg_cache)
- } else {
- Button::labeled("Load SVG file").dom()
- .with_callback(load_svg)
- }
- }
- }
- fn load_svg(app_state: &mut AppState<MyAppData>, _: &mut CallbackInfo<MyAppData>) -> UpdateScreen {
- let mut svg_cache = SvgCache::empty();
- let svg_layers = svg_cache.add_svg(TEST_SVG).unwrap();
- app_state.data.modify(|data| data.svg = Some((svg_cache, svg_layers)));
- Redraw
- }
This is one of the few exceptions where azul allows persistent data across framessince it wouldn't be performant enough otherwise. Ideally you'd have to load, triangulateand draw the SVG file on every frame, but this isn't performant. You might havenoticed that the .dom()
function takes in an extra parameter: The svg_cache
and the info.window
. This way, the svg_cache
handles everything necessary tocache vertex buffers / the triangulated layers and shapes, only the drawing itselfis done on every frame.
Additionally, you can also register callbacks on any item inside the SVG using theSvgCallbacks
, i.e. when someone clicks on or hovers over a certain shape. In orderto draw your own vector data (for example in order to make a vector graphics editor),you can build the "SVG layers" yourself (ex. from the SVG data). Each layer isbatch-rendered, so you can draw many lines or polygons in one draw call, as long asthey share the same SvgStyle
.