SvgBuilder
The SvgBuilder provides SVG support with 60+ elements covering shapes,
text, gradients, filters, animation, clipping, and descriptive elements.
SvgBuilder is a contributed builder — it lives in genro_builders.contrib
and is not loaded unless explicitly imported. It depends on the core framework
(BagBuilderBase, @element, BagRendererBase) but adds no external dependencies.
Basic Usage
from genro_builders.contrib.svg import SvgBuilder
builder = SvgBuilder()
svg = builder.source.svg(width="200", height="200", viewBox="0 0 200 200")
svg.rect(x="10", y="10", width="80", height="80", fill="steelblue")
svg.circle(cx="150", cy="50", r="40", fill="coral")
builder.build()
print(builder.render())
Output:
<svg width="200" height="200" viewBox="0 0 200 200">
<rect x="10" y="10" width="80" height="80" fill="steelblue" />
<circle cx="150" cy="50" r="40" fill="coral" />
</svg>
Attribute Naming
SVG uses kebab-case (stroke-width, fill-opacity) but Python requires
identifiers. Use underscores — the renderer converts them automatically
for known presentation attributes:
svg.rect(width="50", height="50",
stroke_width="2", # -> stroke-width
fill_opacity="0.5", # -> fill-opacity
stroke_dasharray="5,3", # -> stroke-dasharray
)
The full list of converted attributes includes stroke_width, fill_opacity,
fill_rule, stroke_linecap, stroke_linejoin, font_size, font_family,
font_weight, text_anchor, text_decoration, stop_color, stop_opacity,
clip_path, clip_rule, marker_end, marker_start, paint_order, and more.
Use class_ for the CSS class attribute (same convention as HTML).
Shapes
All SVG shape primitives are available:
builder = SvgBuilder()
svg = builder.source.svg(width="300", height="200")
svg.rect(x="10", y="10", width="80", height="60", rx="5", fill="#3498db")
svg.circle(cx="150", cy="40", r="30", fill="#e74c3c")
svg.ellipse(cx="250", cy="40", rx="40", ry="25", fill="#2ecc71")
svg.line(x1="10", y1="100", x2="290", y2="100", stroke="#999", stroke_width="1")
svg.polyline(points="10,180 60,120 110,160 160,110 210,150", fill="none", stroke="#333")
svg.polygon(points="250,110 290,180 210,180", fill="#f39c12")
svg.path(d="M10,200 Q80,120 150,200", fill="none", stroke="#8e44ad", stroke_width="2")
Text
svg = builder.source.svg(width="200", height="100")
# Simple text
svg.text("Hello SVG", x="100", y="50", text_anchor="middle", font_size="24")
# Text with styled spans
t = svg.text("Normal ", x="10", y="80", font_size="14")
t.tspan("Bold", font_weight="bold")
Gradients and Patterns
Define gradients inside <defs>, then reference via fill="url(#id)":
svg = builder.source.svg(width="200", height="200")
# Define gradient
defs = svg.defs()
grad = defs.linearGradient(id="sunset", x1="0", y1="0", x2="0", y2="1")
grad.stop(offset="0%", stop_color="#ff6b6b")
grad.stop(offset="100%", stop_color="#ffd93d")
# Use gradient
svg.rect(width="200", height="200", fill="url(#sunset)")
Radial gradients work the same way:
rg = defs.radialGradient(id="spotlight", cx="50%", cy="50%", r="50%")
rg.stop(offset="0%", stop_color="white")
rg.stop(offset="100%", stop_color="transparent")
Filters
SVG filters are defined in <defs> and applied via the filter attribute:
svg = builder.source.svg(width="200", height="160")
defs = svg.defs()
f = defs.filter(id="shadow", x="-20%", y="-20%", width="140%", height="140%")
f.feGaussianBlur(stdDeviation="4", result="blur")
f.feOffset(dx="4", dy="4", result="offsetBlur")
merge = f.feMerge()
merge.feMergeNode(in_="offsetBlur")
merge.feMergeNode(in_="SourceGraphic")
# Card with shadow
svg.rect(x="30", y="20", width="140", height="100", rx="8",
fill="white", stroke="#ddd", filter="url(#shadow)")
Available filter primitives: feGaussianBlur, feOffset, feBlend,
feColorMatrix, feComposite, feFlood, feMerge, feMergeNode,
feDropShadow, feDiffuseLighting, feSpecularLighting, fePointLight,
feDistantLight, feSpotLight, feMorphology, feTurbulence,
feDisplacementMap, feConvolveMatrix, feImage, feTile.
Groups and Transforms
Use <g> to group elements and apply shared transforms or styles:
svg = builder.source.svg(width="200", height="200")
g = svg.g(transform="translate(50, 50) rotate(45)")
g.rect(width="40", height="40", fill="coral")
g.rect(x="50", width="40", height="40", fill="steelblue")
Symbols and Reuse
Define reusable symbols in <defs>, render them with <use>:
svg = builder.source.svg(width="300", height="100")
defs = svg.defs()
sym = defs.symbol(id="star", viewBox="0 0 24 24")
sym.path(d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.27 5.82 22 7 14.14 2 9.27l6.91-1.01L12 2z")
# Render the symbol at different positions and sizes
svg.use(href="#star", x="10", y="20", width="30", height="30", fill="gold")
svg.use(href="#star", x="60", y="10", width="50", height="50", fill="coral")
svg.use(href="#star", x="130", y="25", width="25", height="25", fill="steelblue")
Clipping and Masking
svg = builder.source.svg(width="200", height="200")
defs = svg.defs()
clip = defs.clipPath(id="circle-clip")
clip.circle(cx="100", cy="100", r="80")
# Image clipped to circle shape
svg.image(href="photo.jpg", width="200", height="200", clip_path="url(#circle-clip)")
Animation
svg = builder.source.svg(width="200", height="100")
c = svg.circle(cx="20", cy="50", r="15", fill="coral")
c.animate(attributeName="cx", from_="20", to="180", dur="2s", repeatCount="indefinite")
Reactive Data Binding
SvgBuilder works with the full reactive infrastructure:
builder = SvgBuilder()
builder.data["radius"] = "40"
builder.data["color"] = "steelblue"
svg = builder.source.svg(width="200", height="200")
svg.circle(cx="100", cy="100", r="^radius", fill="^color")
builder.build()
builder.subscribe()
print(builder.output)
# Change data -> automatic re-render
builder.data["color"] = "coral"
print(builder.output)
Element Reference
Structural
svg, g, defs, symbol, use
Shapes (leaf)
rect, circle, ellipse, line, polyline, polygon, path, image
Text
text (container: tspan, textPath), tspan, textPath
Gradients
linearGradient, radialGradient (container: stop), stop, pattern
Clipping / Masking
clipPath, mask, marker
Filters
filter (container), feGaussianBlur, feOffset, feBlend, feColorMatrix,
feComposite, feFlood, feMerge (container: feMergeNode), feMergeNode,
feDropShadow, feDiffuseLighting, feSpecularLighting, fePointLight,
feDistantLight, feSpotLight, feMorphology, feTurbulence,
feDisplacementMap, feConvolveMatrix, feImage, feTile
Animation
animate, animateTransform, animateMotion, set
Descriptive
title, desc, metadata
Linking
a, foreignObject, switch