Or any other Ruby program really. I know there are attempts already out there but none that really suited my purposes. I needed a simple way of creating that tag-cloud-look for many situations. I needed a tag cloud by size or by colour and I didn’t want it to do everything, just provide me with the style attributes I needed to get the job done. Below is an example of what gets returned by default:
font-size:16px;color:rgb(70,70,70);
Here’s the code; it comes with no warranty.
With all these tags cloud scripts you really only need 3 parameters:
- The total counts of items – For example you have 10 tags each that has been used numerous times. The total counts would be all of the uses added together
- The minimum count of items in a batch – Using the example above this would be a count of the uses for the tag that has been used least
- The maximum count of items in a batch – Using the example above this would be a count of the uses for the tag that has been used most
Below is the actual script and then below that I have stuck a quick example of how you could use it.
def font_size_for_tag_cloud( total, lowest, highest, options={} )
return nil if total.nil? or highest.nil? or lowest.nil?
#
# options
maxf = options.delete( :max_font_size ) || 14
minf = options.delete( :min_font_size ) || 11
maxc = options.delete( :max_color ) || [ 0, 0, 0 ]
minc = options.delete( :min_color ) || [ 156, 156, 156 ]
hide_sizes = options.delete( :hide_sizes )
hide_colours = options.delete( :hide_colours )
#
# function to work out rgb values
def rgb_color( a, b, i, x)
return nil if i <= 1 or x <= 1
if a & b
a-(Math.log(i)*(a-b)/Math.log(x)).floor
else
(Math.log(i)*(b-a)/Math.log(x)+a).floor
end
end
#
# work out colours
c = []
(0..2).each { |i| c && rgb_color( minc[i], maxc[i], total, highest ) || nil }
colors = c.compact.empty? ? minc.join(',') : c.join(',')
#
# work out the font size
spread = highest.to_f - lowest.to_f
spread = 1.to_f if spread <= 0
fontspread = maxf.to_f - minf.to_f
fontstep = spread / fontspread
size = ( minf + ( total.to_f / fontstep ) ).to_i
size = maxf if size > maxf
#
# display the results
size_txt = "font-size:#{ size.to_s }px;" unless hide_sizes
color_txt = "color:rgb(#{ colors });" unless hide_colours
return [ size_txt, color_txt ].join
end
and now a quick example of it’s use in a rails view. This code assumes the db find call looks something like this:
@foo = Foo.find( :all,
:select => '*, COUNT(DISTINCT(i.id)) AS item_cnt',
:joins => 'AS f INNER JOIN bars AS b ON f.id=b.foo_id',
:group => 'b.id',
:order => 'item_cnt DESC',
:limit => 50
)
Below just loop through your db results and calls font_size_for_tag_cloud for each item, passing in the required parameters. There are a few options available but if you leave them out you should still see something useful.
<ul>
<% for f in @foo -%>
<%= content_tag( 'li', f.some_label, :style => font_size_for_tag_cloud( f.bars.size,
f.first.count_items,
f.last.count_items,
) ) %>
<% end -%>
</ul>
That’s it! I guess I should turn it into a plugin but hey, there’s to much reading to be done on ActiveResource at the moment heyhey!