jcraigk/kudochest

View on GitHub
app/services/image/leaderboard_service.rb

Summary

Maintainability
A
3 hrs
Test Coverage
class Image::LeaderboardService < Base::ImageService
  option :profile_data
  option :title

  WIDTH = 400

  HEADER_HEIGHT = 30
  ROW_HEIGHT = 26

  STRIPE_COLORS = {
    day: '#e7e7e7',
    night: '#363636'
  }.freeze

  private

  def composite_image
    height = HEADER_HEIGHT + (BODY_PAD * 2) + (profile_data.size * ROW_HEIGHT)
    comp = solid_color_background(WIDTH, height)

    comp = add_header_bg(comp)
    comp = resize_and_round(comp, "#{WIDTH}x#{height}", 5)

    comp = add_team_avatar(comp)

    comp = add_header_text(comp)
    comp = add_body(comp)

    add_animated_gif(comp)
  end

  def add_animated_gif(comp)
    comp.delay = GIF_SPEED
    random_gif(32).map do |frame|
      comp.composite(frame, WIDTH - 40, 6, Magick::OverCompositeOp)
    end
  end

  def add_team_avatar(comp)
    comp.composite \
      avatar_image(config[:avatar_url]),
      Magick::NorthWestGravity,
      HEADER_PAD,
      HEADER_PAD,
      Magick::OverCompositeOp
  end

  def add_header_text(comp)
    draw = Magick::Draw.new
    draw.font = FONT_FILE
    draw.pointsize = 26
    draw.gravity = Magick::NorthWestGravity

    color = body_colors.first
    draw.annotate(comp, 0, 0, 50, 6, title.delete('*')) do
      self.fill = color
    end

    comp
  end

  def add_body(comp) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
    draw = Magick::Draw.new
    draw.font = FONT_FILE
    draw.gravity = Magick::NorthWestGravity

    color1 = body_colors.first
    color2 = body_colors.second

    y = 48
    profile_data.each_with_index do |data, idx| # rubocop:disable Metrics/BlockLength
      draw.pointsize = 17
      x = BODY_PAD + 5

      # Stripes
      if idx.odd?
        color = STRIPE_COLORS[theme]
        stripe = Magick::Image.new(WIDTH, ROW_HEIGHT) { self.background_color = color }
        stripe = resize_and_round(stripe, "#{WIDTH - 10}x#{ROW_HEIGHT}", 5)
        comp = comp.composite(stripe, Magick::NorthWestGravity, 5, y - 2, Magick::OverCompositeOp)
      end

      # Rank
      if data.rank <= 3
        trophy = Magick::ImageList.new("#{BASE_PATH}/trophies/#{data.rank}.png")
        comp = comp.composite \
          trophy,
          Magick::NorthWestGravity,
          x,
          y + 3,
          Magick::OverCompositeOp
      else
        draw.text_align(Magick::RightAlign)
        value = "#{data.rank}."
        draw.annotate(comp, 0, 0, x, y, value) do
          self.fill = color1
        end
      end
      x += 35

      # Avatar
      comp = comp.composite \
        avatar_image(data.avatar_url, 16),
        Magick::NorthWestGravity,
        x,
        y + 2,
        Magick::OverCompositeOp
      x += 25

      # Name
      draw.text_align(Magick::LeftAlign)
      draw.annotate(comp, 0, 0, x, y, data.display_name) do
        self.fill = color2
      end
      x += 165

      # Points
      draw.annotate(comp, 0, 0, x, y, points_format(data.points)) do
        self.fill = color1
      end
      x += 45

      # Timestamp
      draw.pointsize = 13
      value = time_ago_in_words \
        Time.use_zone(config[:time_zone]) { Time.at(data.last_timestamp).utc }
      value = (value == 'less than a minute' ? 'just now' : "#{value} ago")
      draw.annotate(comp, 0, 0, x + 15, y + 4, value) do
        self.fill = color1
      end

      y += ROW_HEIGHT
    end

    comp
  end
end