DannyBen/icodi

View on GitHub
lib/icodi.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'victor'
require 'digest/md5'
require 'icodi/options'
require 'icodi/randomization'

class Icodi < Victor::SVGBase
  include IcodiCore::Options
  include IcodiCore::Randomization

  attr_reader :text, :options

  def initialize(text = nil, opts = {})
    if text.is_a? Hash
      opts = text
      text = nil
    end

    svg_template = opts.delete :template

    @text = text
    @options = default_options.merge opts

    super template: svg_template, viewBox: "0 0 #{size} #{size}", id: id

    generate
  end

private

  def generate
    clip_path_id = "#{id}-#{random_id}"

    element :rect, x: 0, y: 0, width: size, height: size, fill: background
    element :defs do
      element :clipPath, id: clip_path_id do
        element :rect, width: size, height: size
      end
    end

    half = (pixels / 2.0).round
    x = mirror_x? ? half : pixels
    y = mirror_y? ? half : pixels

    element :g, clip_path: "url(##{clip_path_id})" do
      draw x, y
    end
  end

  def draw(x_times, y_times)
    y_times.times do |y|
      x_times.times do |x|
        add_pixels x, y if random.rand < density
      end
    end
  end

  def add_pixels(x, y)
    x, y = add_jitter x, y

    draw_pixel x, y
    draw_pixel mirror_value(x), y if mirror? x: x
    draw_pixel x, mirror_value(y) if mirror? y: y
    draw_pixel mirror_value(x), mirror_value(y) if mirror? x: x, y: y
  end

  def add_jitter(x, y)
    if jitter.positive? && (random(:jitter).rand < jitter)
      add_jitter! x, y
    else
      [x, y]
    end
  end

  def add_jitter!(x, y)
    x += random_jitter unless mirror_x? && mid?(x: x)
    y += random_jitter unless mirror_y? && mid?(y: y)
    [x, y]
  end

  def draw_pixel(x, y)
    element :rect, x: x * 10, y: y * 10, width: 10, height: 10, fill: color, style: style
  end

  # Drawing Utilities

  def mirror?(x: nil, y: nil)
    if x && y
      mirror_both? and !mid?(x: x) and !mid?(y: y)
    elsif x
      mirror_x? and !mid? x: x
    elsif y
      mirror_y? and !mid? y: y
    end
  end

  def mid?(x: nil, y: nil)
    if x
      x == pixels / 2
    elsif y
      y == pixels / 2
    end
  end

  def mirror_value(value)
    pixels - 1 - value
  end

  def random_id
    random(:nonvisual).rand(9_999_999)
  end

  def random_jitter
    [0, 0.5, -0.5][random(:jitter).rand(3)]
  end

  def random_color
    '#%06x' % (random(:color).rand * 0xffffff)
  end
end