Another tag cloud script for Ruby on Rails
July 6th, 2006 @ 09:09 skip to comments
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!

Could you explain me the mean of the parameters of the function?
total, is the counts for a specify tags?
lowest, is the lowest value for all tags?
highest, is the highest values for all tags?
Looks handy!
Is this posted under any particular (hopefully opensource
license, or just here for education and enlightenment?
PacoGuzman: I have updated the description. Hopefully that will help.
Dan: Feel free to use this code where ever you like. You might like to give me a heads up in the source somewhere just to be polite.