Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
This Gist summaries the files as created in the blog post [INSERT LINK]. It shows how to use the Presenter design pattern in a Rails application.
# app/controllers/graphs_controller.rb
def show
...
@presenter = GraphPresenters::LineGraphPresenter.new graph
end
# app/presenters/graph_presenters/line_graph_presenter.rb
module GraphPresenters
class LineGraphPresenter
public
def initialize( graph )
@graph = graph
@options = {
:number_of_vertical_lines = 11,
:range_top_value = @graph.max_value
}
@options[:range_step_size] = @options[:range_top_value] / @options[:number_of_vertical_lines]
end
def configure( settings = {} )
settings.assert_valid_keys( :width, :height )
@options.merge! settings
@options.merge! {
x_start: 113, # Leave space for the vertical labels
y_start: 10, # Leave space for the year-labels
radius: 5, # The radius of each data point
}
@options.merge! {
x_end: @options[:width] - @options[:radius],
y_end: @options[:height] - @options[:radius]
}
end
def vertical_line(n)
{
x1: vertical_line_position_x(n),
y1: @options[:y_start],
x2: vertical_line_position_x(n),
y2: @options[:y_end]
}
def horizontal_line(n)
{
x1: @options[:x_start],
y1: horizontal_line_position_y(n),
x2: @options[:x_end],
y2: horizontal_line_position_y(n)
}
end
def circle(n)
value = @graph.datapoint n
line = vertical_line n
{
cx: line[:x1],
cy: y_position value,
r: 5
}
end
def surface
point = circle 0
first = point
path = "M#{point[:cx]},#{@options[:y_end]}"
@graph.number_of_datapoints.times do |n|
point = circle n
path += "L#{point[:cx]},#{point[:cy]}"
end
path << "L#{point[:cx]},#{@options[:y_end}"
path << "M#{first[:cx]},#{@options[:y_end}"
{ d: path }
end
private
def distance_between_vertical_lines
pixels_available = (@options[:x_end] - @options[:x_start])
pixels_available / @graph.number_of_datapoints
end
def distance_between_horizontal_lines
pixels_available = @options[:y_end] - @options[:y_start]
pixels_available / @options[:number_of_vertical_lines]
end
# Vertical lines are aligned with each year on the x-axis
def vertical_line_position_x(n)
@options[:x_start] + (distance_between_vertical_lines * n)
end
# Horizontal lines provide visual guidance for the value of data points
def horizontal_line_position_y(n)
@options[:y_start] + (distance_between_horizontal_lines * n)
end
def y_position(value)
# Assume the y-axis always starts from 0
pixels_per_value = (@options[:end] - @options[:start]) / @options[:range_top_value]
@options[:y_end] - (value * pixels_per_value)
end
end
end
# app/views/graphs/show.html.haml
%svg{xmlns: 'http://www.w3.org/2000/svg','xmlns:xlink' => 'http://www.w3.org/1999/xlink', version: '1.1', class: 'graph'}
%g.grid#xGrid
- @presenter.number_of_datapoints.times do |n|
%line{ @presenter.vertical_line n }
%g.grid#yGrid
- @presenter.number_of_vertical_lines.times do |n|
%line{ @presenter.horizontal_line n }
%g.surfaces
%path{ @presenter.surface }
%g.points
- @graph.number_of_datapoints.times do |n|
%circle{ @presenter.circle(n) }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment