From 87240723e7970dc48e2f29c6872e99ff72b4ec94 Mon Sep 17 00:00:00 2001 From: Scott Davis Date: Tue, 2 Aug 2011 23:35:27 -0400 Subject: [PATCH] smart packing helper classes --- .../sass_extensions/sprites/image_row.rb | 47 ++++++++++ .../sass_extensions/sprites/row_fitter.rb | 86 +++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 lib/compass/sass_extensions/sprites/image_row.rb create mode 100644 lib/compass/sass_extensions/sprites/row_fitter.rb diff --git a/lib/compass/sass_extensions/sprites/image_row.rb b/lib/compass/sass_extensions/sprites/image_row.rb new file mode 100644 index 00000000..51ae0d73 --- /dev/null +++ b/lib/compass/sass_extensions/sprites/image_row.rb @@ -0,0 +1,47 @@ +require 'forwardable' + +module Compass + module SassExtensions + module Sprites + class ImageRow + extend Forwardable + + attr_reader :images, :max_width + def_delegators :@images, :last, :delete, :empty?, :length + + def initialize(max_width) + @images = [] + @max_width = max_width + end + + def add(image) + return false if !will_fit?(image) + @images << image + true + end + + alias :<< :add + + def height + images.map(&:height).max + end + + def width + images.map(&:width).max + end + + def total_width + images.inject(0) {|sum, img| sum + img.width } + end + + def efficiency + 1 - (total_width.to_f / max_width.to_f) + end + + def will_fit?(image) + (total_width + image.width) <= max_width + end + end + end + end +end \ No newline at end of file diff --git a/lib/compass/sass_extensions/sprites/row_fitter.rb b/lib/compass/sass_extensions/sprites/row_fitter.rb new file mode 100644 index 00000000..b5afff0f --- /dev/null +++ b/lib/compass/sass_extensions/sprites/row_fitter.rb @@ -0,0 +1,86 @@ +require 'forwardable' + +module Compass + module SassExtensions + module Sprites + class RowFitter + extend Forwardable + + attr_reader :images, :rows + def_delegators :rows, :[] + + def initialize(images) + @images = images.sort {|a,b| a.height <=> b.height } + @rows = [] + end + + def fit!(style = :scan) + send("#{style}_fit") + @rows + end + + def width + @width ||= @images.collect(&:width).max + end + + def height + @height ||= @rows.inject(0) {|sum, row| sum += row.height} + end + + def efficiency + @rows.inject(0) { |sum, row| sum += row.efficiency } ** @rows.length + end + + private + def new_row(image = nil) + row = Compass::SassExtensions::Sprites::ImageRow.new(width) + row.add(image) if image + row + end + + def fast_fit + row = new_row + @images.each do |image| + if !row.add(image) + @rows << row + row = new_row(image) + end + end + + @rows << row + end + + def scan_fit + fast_fit + + moved_images = [] + + begin + removed = false + + catch :done do + @rows.each do |row| + (@rows - [ row ]).each do |other_row| + other_row.images.each do |image| + if !moved_images.include?(image) + if row.will_fit?(image) + other_row.delete(image) + row << image + + @rows.delete(other_row) if other_row.empty? + removed = true + + moved_images << image + throw :done + end + end + end + end + end + end + end while removed + end + end + end + end +end \ No newline at end of file