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!