Connectors and Freeform Shapes

Copy Markdown View Source

Draw lines between elements with Podium.add_connector/7 and build custom vector shapes with the Podium.Freeform builder.

Try it yourself

Run mix run demos/connectors-and-freeforms.exs to generate a presentation with all the examples from this guide.

slide = Podium.add_connector(slide, :straight,
  {2, :inches}, {3, :inches}, {6, :inches}, {3, :inches},
  line: [color: "003366", width: {1.5, :pt}])

Connectors

Connectors are lines that run between two coordinate points. Podium supports three types: :straight (direct line), :elbow (right-angle routed), and :curved (S-curve).

Adding Connectors

Podium.add_connector/7 takes the slide, connector type, start coordinates, end coordinates, and optional line formatting:

prs = Podium.new()

slide =
  Podium.Slide.new()
  |> Podium.add_auto_shape(:rounded_rectangle,
    x: {1, :inches}, y: {2, :inches},
    width: {2, :inches}, height: {1, :inches},
    text: "Planning", fill: "4472C4")
  |> Podium.add_auto_shape(:rounded_rectangle,
    x: {6, :inches}, y: {2, :inches},
    width: {2, :inches}, height: {1, :inches},
    text: "Execution", fill: "70AD47")
  |> Podium.add_connector(:straight,
    {3, :inches}, {2.5, :inches}, {6, :inches}, {2.5, :inches},
    line: [color: "000000", width: {1.5, :pt}])

Flowchart with straight, elbow, and curved connectors

Podium automatically calculates flip attributes when the end point is to the left of or above the start point.

Elbow and Curved Connectors

# Elbow connector with dashed line
slide = Podium.add_connector(slide, :elbow,
  {2, :inches}, {4, :inches}, {7, :inches}, {6, :inches},
  line: [color: "FF0000", width: {2, :pt}, dash_style: :dash])

# Curved connector
slide = Podium.add_connector(slide, :curved,
  {7.5, :inches}, {5, :inches}, {10, :inches}, {2.5, :inches},
  line: [color: "5B9BD5", width: {2, :pt}])

Connector Line Formatting

Connector lines accept the same options as shape lines: :color, :width, :dash_style, and :fill (for gradient or pattern lines). When no :line option is provided, connectors use the theme's default styling.

Freeform Shapes

Freeform shapes let you draw custom vector paths. The Podium.Freeform module uses a builder pattern: create a builder, chain path operations, then add it to a slide with Podium.add_freeform/3 (slide, freeform, opts).

Drawing a Triangle

alias Podium.Freeform

triangle =
  Freeform.new({2, :inches}, {4, :inches})
  |> Freeform.line_to({5, :inches}, {1, :inches})
  |> Freeform.line_to({8, :inches}, {4, :inches})
  |> Freeform.close()

slide = Podium.add_freeform(slide, triangle, fill: "4472C4", line: "002060")

Freeform triangle and five-pointed star

Path Operations

FunctionDescription
Freeform.new(x, y, opts)Start a new path at (x, y)
Freeform.line_to(fb, x, y)Draw a line segment to (x, y)
Freeform.move_to(fb, x, y)Move without drawing (starts a new contour)
Freeform.close(fb)Close the current contour back to its start
Freeform.add_line_segments(fb, vertices, opts)Add multiple segments at once

Batch Line Segments

Use Freeform.add_line_segments/3 with a list of {x, y} vertices:

alias Podium.Freeform

star =
  Freeform.new({6.67, :inches}, {1.5, :inches})
  |> Freeform.add_line_segments([
    {{5.49, :inches}, {5.12, :inches}},
    {{8.57, :inches}, {2.88, :inches}},
    {{4.77, :inches}, {2.88, :inches}},
    {{7.85, :inches}, {5.12, :inches}}
  ], close: true)

slide = Podium.add_freeform(slide, star, fill: "FFD700", line: "CC9900")

Coordinate Scaling

When working with abstract grid coordinates, use :scale to convert to EMU:

alias Podium.Freeform

# 1 unit = 0.01 inches (9144 EMU)
fb =
  Freeform.new(0, 0, scale: 9144)
  |> Freeform.line_to(300, 0)
  |> Freeform.line_to(150, 260)
  |> Freeform.close()

slide = Podium.add_freeform(slide, fb,
  origin_x: {2, :inches}, origin_y: {2, :inches}, fill: "ED7D31")

For non-square scaling, use :x_scale and :y_scale instead of :scale.

Multiple Contours

Use Freeform.move_to/3 to start a new contour within the same shape:

alias Podium.Freeform

# Square with a square cutout
cutout =
  Freeform.new({4.67, :inches}, {1.5, :inches})
  |> Freeform.add_line_segments([
    {{8.67, :inches}, {1.5, :inches}},
    {{8.67, :inches}, {5.5, :inches}},
    {{4.67, :inches}, {5.5, :inches}}
  ])
  |> Freeform.close()
  |> Freeform.move_to({5.67, :inches}, {2.5, :inches})
  |> Freeform.add_line_segments([
    {{7.67, :inches}, {2.5, :inches}},
    {{7.67, :inches}, {4.5, :inches}},
    {{5.67, :inches}, {4.5, :inches}}
  ])
  |> Freeform.close()

slide = Podium.add_freeform(slide, cutout, fill: "70AD47")

Multi-contour freeform with rectangular cutout

Freeform Options

OptionTypeDefaultDescription
:origin_xemu_spec0X offset for the bounding box
:origin_yemu_spec0Y offset for the bounding box
:fillfill_specnilFill color or fill tuple
:lineline_specnilLine color or line opts
:rotationnumbernilRotation in degrees

For embedding video and other media, see the Video Embedding guide.