Skip to content

Commit

Permalink
replace gruff with svg-graph2
Browse files Browse the repository at this point in the history
  • Loading branch information
akostadinov committed Jan 18, 2023
1 parent 972578c commit bd47643
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 82 deletions.
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ gem 'braintree', '~> 2.93'
gem 'bugsnag', '~> 6.11'
gem 'cancancan', '~> 2.3.0'
gem 'formtastic', '~> 2.3.1'
gem 'gruff', '~>0.3', require: false
gem 'htmlentities', '~>4.3', '>= 4.3.4'
gem 'rmagick', '~> 2.15.3', require: false
# TODO: Not actively maintained https://github.com/activeadmin/inherited_resources#notice replace with respond_with and fix things the rails way
gem 'inherited_resources', '~> 1.12.0'
gem 'has_scope', '~> 0.7.2' # remove line after we stop supporting Ruby 2.4
Expand Down Expand Up @@ -100,6 +98,7 @@ gem 'json-schema', git: 'https://github.com/3scale/json-schema.git'
gem 'paperclip', '~> 6.0'
gem 'prawn'
gem 'prawn-table', git: "https://github.com/prawnpdf/prawn-table.git", branch: "38b5bdb5dd95237646675c968091706f57a7a641"
gem 'prawn-svg'
gem 'rails_event_store', '~> 0.9.0', require: false
gem 'ratelimit'
gem 'recaptcha', '4.13.1', require: 'recaptcha/rails'
Expand All @@ -109,6 +108,7 @@ gem 'redis', '~> 4.1.3', require: ['redis', 'redis/connection/hiredis']
gem 'redis-namespace', '~> 1.7.0'
gem 'rest-client', '~> 2.0.2'
gem 'rubyzip', '~>1.3.0', require: false
gem 'svg-graph', require: false
gem 'swagger-ui_rails', git: 'https://github.com/3scale/swagger-ui_rails.git', branch: 'dev'
gem 'swagger-ui_rails2', git: 'https://github.com/3scale/swagger-ui_rails.git', branch: 'dev-2.1.3'
gem 'thinking-sphinx', '~> 5.4.0'
Expand Down
14 changes: 9 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ GEM
crack (0.4.5)
rexml
crass (1.0.6)
css_parser (1.12.0)
addressable
cucumber (7.0.0)
builder (~> 3.2, >= 3.2.4)
cucumber-core (~> 10.0, >= 10.0.1)
Expand Down Expand Up @@ -365,8 +367,6 @@ GEM
github-markdown (0.6.9)
globalid (0.4.2)
activesupport (>= 4.2.0)
gruff (0.7.0)
rmagick (~> 2.13, >= 2.13.4)
has_scope (0.7.2)
actionpack (>= 4.1)
activesupport (>= 4.1)
Expand Down Expand Up @@ -528,6 +528,10 @@ GEM
prawn (2.4.0)
pdf-core (~> 0.9.0)
ttfunk (~> 1.7)
prawn-svg (0.32.0)
css_parser (~> 1.6)
prawn (>= 0.11.1, < 3)
rexml (~> 3.2)
prometheus-client-mmap (0.11.0)
protected_attributes_continued (1.8.2)
activemodel (>= 5.0)
Expand Down Expand Up @@ -653,7 +657,6 @@ GEM
netrc (~> 0.8)
rexml (3.2.5)
riddle (2.4.3)
rmagick (2.15.4)
roar (1.0.4)
representable (>= 2.0.1, < 2.4.0)
roar-rails (1.0.2)
Expand Down Expand Up @@ -792,6 +795,7 @@ GEM
stripe (5.28.0)
strong_migrations (0.6.8)
activerecord (>= 5)
svg-graph (2.2.1)
sys-uname (1.2.2)
ffi (~> 1.1)
temple (0.8.1)
Expand Down Expand Up @@ -949,7 +953,6 @@ DEPENDENCIES
formtastic (~> 2.3.1)
github-markdown
globalid (~> 0.4.2)
gruff (~> 0.3)
has_scope (~> 0.7.2)
hashie
hiredis (~> 0.6.3)
Expand Down Expand Up @@ -987,6 +990,7 @@ DEPENDENCIES
pg (~> 0.21.0)
pisoni (~> 1.29)
prawn
prawn-svg
prawn-table!
protected_attributes_continued (~> 1.8.2)
pry-byebug (>= 3.7.0)
Expand All @@ -1013,7 +1017,6 @@ DEPENDENCIES
reek (= 6.01)
reform (~> 2.0.3)
rest-client (~> 2.0.2)
rmagick (~> 2.15.3)
roar-rails
rspec-html-matchers!
rspec-rails (~> 4.1)
Expand Down Expand Up @@ -1045,6 +1048,7 @@ DEPENDENCIES
statsd-ruby
stripe (~> 5.28.0)
strong_migrations (~> 0.6.8)
svg-graph
swagger-ui_rails!
swagger-ui_rails2!
thin
Expand Down
71 changes: 3 additions & 68 deletions app/lib/pdf/data.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# frozen_string_literal: true

require 'gruff'

module Pdf
class Data

Expand Down Expand Up @@ -74,74 +72,11 @@ def metrics
end
end

def traffic_graph
return if @hit_metric.nil?

data = @source.usage(@options)

g = Gruff::Line.new('1200x300')

g.theme = {
:colors => ['#9172EC', '#306EFF', '#000066', '#B4B4B4'],
:font_color => '#555',
:marker_color => '#eeeeee',
:background_colors => ['#ffffff', '#ffffff']
}

g.legend_box_size = 10
g.hide_title = true
g.legend_font_size = 13
g.hide_line_markers = false
g.marker_font_size = 13
g.hide_dots = false
g.dot_radius = 3
g.line_width = 2
g.marker_count = 5
g.margins = 2

g.sort = false
g.x_axis_label = @period == :day ? "Hour" : "Week Days"
g.y_axis_label = @hit_metric.friendly_name

data = data[:values]
g.data(@hit_metric.friendly_name, data)

max = data.max
g.maximum_value = max + (max / 5)

g.labels = send("#{@period}_labels")
StringIO.new(g.to_blob("JPG"))
def usage
@source.usage(@options) unless @hit_metric.nil?
end

def week_labels
# Week report, there are 28 data points, at 6 hour intervals
# What was the date 1 week ago
date = 1.week.ago.beginning_of_day

#Gruff expects labels to be presented as a hash
labels= {}
(0..27).each do |point|
# Insert blanks except for every 4th data point (covering a 24hr period)
if (point % 4).zero?
labels[point] = date.strftime("%d %b")
date += 1.day
end
end

labels
end

def day_labels
# See week_labels
date = 1.day.ago.beginning_of_day

labels = {}
(0..23).each do |point|
labels[point] = date.strftime("%k:00") if (point % 4).zero?
date += 1.hour
end
labels
end
private

def sanitize_text(text)
EscapeUtils.escape_javascript(text.to_s)
Expand Down
167 changes: 163 additions & 4 deletions app/lib/pdf/report.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# frozen_string_literal: true

require 'SVG/Graph/DataPoint'
require 'SVG/Graph/Line'

# REFACTOR: extract abstract Report class, and DRY functionality with InvoiceReporter
module Pdf
class Report
Expand Down Expand Up @@ -35,6 +38,7 @@ def generate

header

move_down 3
traffic_graph
move_down 3

Expand Down Expand Up @@ -128,11 +132,158 @@ def traffic_and_users
end
end

def graph_key_formatter(usage)
if @period == :day
->(point) { (point % 4).zero? ? "" : sprintf("%02d:00", point) }
else
since = Time.parse(usage.dig(:period, :since))
granularity = usage.dig(:period, :granularity)
->(point) { (point % 4).zero? ? "" : (since + point * granularity).strftime("%d %b") }
end
end

def traffic_graph
graph = @data.traffic_graph
return unless graph
subtitle "Traffic"
@pdf.image graph, position: :left, width: 520
usage = @data.usage

return unless usage

options = {
graph_title: "Traffic",
show_graph_title: true,
key: false,
area_fill: false,
show_data_values: false,
add_popups: false,
width: TABLE_FULL_WIDTH,
height: TABLE_FULL_WIDTH / 4,
step_x_labels: 4,
step_include_first_x_label: true,
fields: usage[:values].each_index.map(&:succ).map(&graph_key_formatter(usage)),
show_x_title: false,
x_title: @period == :day ? "Hour" : "Week Days",
show_y_guidelines: true,
scale_integers: true,
scale_divisions: [2, (usage[:values].max - usage[:values].min) / 5].max,
number_format: IntegerWithDelimiterFormatter.new,
show_y_title: false,
y_title: usage.dig(:metric, :name),
y_title_location: :middle,
no_css: false,
}

graph = SVG::Graph::Line.new(options)

graph.add_data(data: usage[:values], title: options[:y_title])

@pdf.svg traffic_graph_style(graph.burn_svg_only)
end

def traffic_graph_style(svg)
xml = Nokogiri::XML(svg)
style = xml.at_css("style")
css = CssParser::Parser.new
css.load_string!(style.text.gsub(/ff0000/i, "9273ED"))
traffic_graph_first_data_point(xml)
traffic_graph_y_align(xml)
traffic_graph_style_clean_up(css)
traffic_graph_style_guide_lines(css)
traffic_graph_style_axes(css)
traffic_graph_style_line_width(css)
traffic_graph_style_background(css)
traffic_graph_style_text(css)

style.content = css.to_s
xml.to_s
end

# TODO: remove this hack ofter fix is acepted upstream
# https://github.com/lumean/svg-graph2/pull/43
def traffic_graph_first_data_point(xml)
line = xml.at_css(".line1")
line[:d] = line[:d].sub(/^M.+L\s*(\S+\s+\S+)(.*)$/, 'M\1 L\2')
end

# TODO: remove this hack after fix is accepted upstream
# https://github.com/lumean/svg-graph2/pull/44
def traffic_graph_y_align(xml)
xml.css(".yAxisLabels").each do |label|
label[:x] = "-8"
label.delete("style")
label.delete("transform")
end
end

def traffic_graph_style_background(css)
desired = <<-EOT
.graphBackground {
fill:#ffffff;
}
EOT

css.remove_rule_set!(css.find_rule_sets([".graphBackground"]).first)
css.add_block!(desired)
end

def traffic_graph_style_text(css)
desired = <<-EOT
.xAxisLabels,.yAxisLabels {
fill:#909090;
font-size: 10px;
font-family: "#{@style[:font]}", sans-serif; font-weight: normal;
}
.mainTitle {
fill:#505050;
font-family: "#{@style[:font]}", sans-serif; font-weight: normal;
}
EOT

css.add_block!(desired)
end

def traffic_graph_style_axes(css)
desired = <<-EOT
.axis{
stroke: #ffffff;
stroke-width: 0px;
}
EOT

css.remove_rule_set!(css.find_rule_sets([".axis"]).first)
css.add_block!(desired)
end

def traffic_graph_style_line_width(css)
desired = <<-EOT
.line1 {
stroke-width: 2px;
}
EOT

css.add_block!(desired)
end

def traffic_graph_style_guide_lines(css)
desired = <<-EOT
.guideLines,#yAxis {
stroke: #eeeeee;
stroke-width: 0.3px;
stroke-dasharray: 0.01 1;
stroke-linejoin: round;
stroke-linecap: round;
}
EOT

css.remove_rule_set!(css.find_rule_sets([".guideLines"]).first)
css.add_block!(desired)
end

def traffic_graph_style_clean_up(css)
(2..12).each do |num|
%w[line fill key dataPoint].each do |type|
rule = css.find_rule_sets([".#{type}#{num}"]).first
css.remove_rule_set!(rule) if rule.present?
end
end
end

def metrics
Expand Down Expand Up @@ -189,5 +340,13 @@ def colorize_num(numstr)
{ content: numstr, **@style[:green] }
end
end

class IntegerWithDelimiterFormatter
include ActionView::Helpers::NumberHelper

def %(num)
number_with_delimiter(num.to_i)
end
end
end
end
3 changes: 0 additions & 3 deletions config/initializers/prawn.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
# require 'prawn'
# require 'prawn/format'
require "prawn/measurement_extensions"
require 'gruff'
require "open-uri"

module Prawn
Expand Down

0 comments on commit bd47643

Please sign in to comment.