module BlacklightRangeLimit::SegmentCalculation

Protected Instance Methods

add_range_segments_to_solr!(solr_params, facet_field, min, max) click to toggle source

Calculates segment facets within a given start and end on a given field, returns request params to be added on to what’s sent to solr to get the calculated facet segments. Assumes solr_field is an integer, as range endpoint will be found by subtracting one from subsequent boundary.

Changes solr_params passed in.

# File lib/blacklight_range_limit/segment_calculation.rb, line 14
def add_range_segments_to_solr!(solr_params, facet_field, min, max)
  raise InvalidRange, "The min date must be before the max date" if min > max
  field_config = blacklight_config.facet_fields[facet_field.to_s]

  return solr_params unless field_config

  range_config = field_config.range_config

  solr_params[:"facet.query"] ||= []

  boundaries = boundaries_for_range_facets(min, max, range_config[:num_segments] || 10)

  # Now make the boundaries into actual filter.queries.
  0.upto(boundaries.length - 2) do |index|
    first = boundaries[index]
    last =  boundaries[index+1].to_i - 1

    solr_params[:"facet.query"] << "#{field_config.field}:[#{first} TO #{last}]"
  end

  solr_params
end
boundaries_for_range_facets(first, last, num_div) click to toggle source

returns an array of ‘boundaries’ for producing approx num_div segments between first and last. The boundaries are ‘nicefied’ to factors of 5 or 10, so exact number of segments may be more or less than num_div. Algorithm copied from Flot.

Because of arithmetic issues with creating boundaries that will be turned into inclusive ranges, the FINAL boundary will be one unit more than the actual end of the last range later computed.

# File lib/blacklight_range_limit/segment_calculation.rb, line 45
def boundaries_for_range_facets(first, last, num_div)
  raise ArgumentError, "The first date must be before the last date" if last < first
  # arithmetic issues require last to be one more than the actual
  # last value included in our inclusive range
  last += 1

  # code cribbed from Flot auto tick calculating, but leaving out
  # some of Flot's options becuase it started to get confusing.
  delta = (last - first).to_f / num_div

  # Don't know what most of these variables mean, just copying
  # from Flot.
  dec = -1 * ( Math.log10(delta) ).floor
  magn = (10 ** (-1 * dec)).to_f
  norm = (magn == 0) ? delta : (delta / magn) # norm is between 1.0 and 10.0

  size = 10
   if (norm < 1.5)
     size = 1
   elsif (norm < 3)
     size = 2;
     # special case for 2.5, requires an extra decimal
     if (norm > 2.25 )
       size = 2.5;
       dec = dec + 1
     end
   elsif (norm < 7.5)
     size = 5
   end

   size = size * magn

   boundaries = []

   start = floorInBase(first, size)
   i = 0
   v = Float::MAX
   prev = nil
   begin
     prev = v
     v = start + i * size
     boundaries.push(v.to_i)
     i += 1
   end while ( v < last && v != prev)

   # Can create dups for small ranges, tighten up
   boundaries.uniq!

   # That algorithm i don't entirely understand will sometimes
   # extend past our first and last, tighten it up and make sure
   # first and last are endpoints.
   boundaries.delete_if {|b| b <= first || b >= last}
   boundaries.unshift(first)
   boundaries.push(last)

   return boundaries
end
floorInBase(n, base) click to toggle source

Cribbed from Flot. Round to nearby lower multiple of base

# File lib/blacklight_range_limit/segment_calculation.rb, line 104
def floorInBase(n, base)
   return base * (n / base).floor
end