Frame - Automatic Box Placement

The HexaPDF::Layout::Frame class is used for placing rectangular boxes.

This example shows how to create a frame and how different box styles can be used to specify where a box should be placed. After each box is drawn, the frame’s shape is drawn and then a new page is started. This is done to easily compare the changes after each added box.

Note how the absolutely positioned box cuts a hole into the frame’s shape and how that influences the positioning.

Usage:
ruby frame_automatic_box_placement.rb
Resulting PDF:
frame_automatic_box_placement.pdf
Preview:

Code

require 'hexapdf'

include HexaPDF::Layout

doc = HexaPDF::Document.new
page = doc.pages.add
page_box = page.box
canvas = page.canvas

frame = Frame.new(page_box.left + 20, page_box.bottom + 20,
                  page_box.width - 40, page_box.height - 40)

box_counter = 1
draw_box = lambda do |**args|
  b = Box.create(**args, border: {width: 1, color: "hp-blue-dark"}) do |canv, box|
    canv.save_graphics_state do
      canv.stroke_color("hp-blue-dark")
      canv.line(0, 0, box.content_width, box.content_height).
        line(0, box.content_height, box.content_width, 0).
        stroke
    end
    text = box_counter.to_s << "\n" + args.map {|k, v| "#{k}: #{v}"}.join("\n")
    canv.font("Times", size: 15).leading(15).
      text(text, at: [10, box.content_height - 20])
    box_counter += 1
  end

  drawn = false
  until drawn
    result = frame.fit(b)
    if result.success?
      frame.draw(canvas, result)
      drawn = true
    else
      frame.find_next_region
    end
  end

  canvas.line_width(3).draw(:geom2d, object: frame.shape)
  canvas = doc.pages.add.canvas
end

# Absolutely positioned box with margin
draw_box.call(width: 100, height: 100, position: [250, 250], margin: 10)

# Fixed sized box with automatic width
draw_box.call(height: 100)

# Fixed sized box
draw_box.call(width: 100, height: 100)

# Fixed sized box, placed below the other because the space to the right can't
# be used
draw_box.call(width: 100, height: 100)

# Fixed sized floating box, space to the right can be used
draw_box.call(width: 100, height: 100, position: :float, align: :left)

# Fixed sized floating box again, floating to the right
draw_box.call(width: 100, height: 100, position: :float, align: :right)

# Fixed sized floating box again, floating to the left with margin
draw_box.call(width: 100, height: 100, position: :float, align: :left,
              margin: [0, 10])

# Fixed sized box, no floating
draw_box.call(width: 100, height: 100)

# Fixed sized box, center aligned in the available space
draw_box.call(width: 100, height: 100, align: :center)

# Fixed sized box, right aligned in the available space
draw_box.call(width: 100, height: 100, align: :right)

# Fixed sized box, consuming the whole remaining available space
draw_box.call

doc.write("frame_automatic_box_placement.pdf", optimize: true)