-
Notifications
You must be signed in to change notification settings - Fork 41
Expand file tree
/
Copy pathsegment_calculation.rb
More file actions
109 lines (88 loc) · 3.46 KB
/
segment_calculation.rb
File metadata and controls
109 lines (88 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# Meant to be in a Controller, included in our ControllerOverride module.
module BlacklightRangeLimit
module SegmentCalculation
protected
# 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.
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
# 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.
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 + 1
end
elsif norm < 7.5
size = 5
end
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)
boundaries
end
# Cribbed from Flot. Round to nearby lower multiple of base
def floorInBase(n, base)
base * (n / base).floor
end
end
end