<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>yatsu.info: RubyでTagCloud (tagcloud-ruby)</title>
    <link>http://yatsu.info/articles/2005/08/05/ruby%E3%81%A7tagcloud-tagcloud-ruby</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description></description>
    <item>
      <title>RubyでTagCloud (tagcloud-ruby)</title>
      <description>&lt;p&gt;&lt;a href="http://d.hatena.ne.jp/naoya/20050701/1120197491"&gt;naoyaのはてなダイアリー &amp;#8211;  &lt;span class="caps"&gt;HTML&lt;/span&gt;::TagCloud&lt;/a&gt; で紹介されているように、PerlにはTagCloud (はてなブックマークの右側に出てくるタグ一覧みたいなやつ) を生成する &lt;a href="http://search.cpan.org/dist/HTML-TagCloud/lib/HTML/TagCloud.pm"&gt;HTML::TagCloud&lt;/a&gt; というものがありますが、Rubyにはそれに相当するものがなさそうだったので、作ってみました。
アルゴリズムはHTML::TagCloudとまったく同じです。&lt;/p&gt;


	&lt;p&gt;Rubyライセンスということにしておきますので、ご自由にお使いください。&lt;/p&gt;


&lt;pre&gt;
# Author: Masaki Yatsu &amp;lt;yatsu@yatsu.info&amp;gt;

class TagCloud
  def initialize
    @counts = Hash.new
    @urls = Hash.new
  end

  def add(tag, url, count)
    @counts[tag] = count
    @urls[tag] = url
  end

  def css
    text = "" 
    for level in 0..24
      font = 12 + level
      text &amp;lt;&amp;lt; "span.tagcloud#{level} {font-size: #{font}px;}\n" 
      text &amp;lt;&amp;lt; "span.tagcloud#{level} a {text-decoration: none;}\n" 
    end
    text
  end

  def html(limit = nil)
    tags = @counts.sort_by {|a, b| b }.reverse.map {|a, b| a }
    tags = tags[0..limit-1] if limit
    if tags.empty?
      return "" 
    elsif tags.size == 1
      tag = tags[0]
      url = @urls[tag]
      return %{&amp;lt;span class="tagcloud24"&amp;gt;&amp;lt;a href="#{url}"&amp;gt;#{tag}&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;\n}
    end

    min = Math.sqrt(@counts[tags.last])
    max = Math.sqrt(@counts[tags.first])
    factor = 0

    # special case all tags having the same count
    if max - min == 0
      min = min - 24
      factor = 1
    else
      factor = 24 / (max - min)
    end

    html = "" 
    tags.sort.each do |tag|
      count = @counts[tag]
      url   = @urls[tag]
      level = ((Math.sqrt(count) - min) * factor).to_i
      html &amp;lt;&amp;lt; %{&amp;lt;span class="tagcloud#{level}"&amp;gt;&amp;lt;a href="#{url}"&amp;gt;#{tag}&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;\n}
    end
    html
  end

  def html_and_css(limit = nil)
    "&amp;lt;style&amp;gt;\n#{self.css}&amp;lt;/style&amp;gt;\n#{self.html(limit)}" 
  end
end
&lt;/pre&gt;

	&lt;p&gt;サンプルは &lt;a href="http://d.hatena.ne.jp/naoya/20050701/1120197491"&gt;naoyaのはてなダイアリー &amp;#8211;  &lt;span class="caps"&gt;HTML&lt;/span&gt;::TagCloud&lt;/a&gt; をまねて、以下のようにしました。&lt;/p&gt;


&lt;pre&gt;
#!/usr/bin/ruby

require 'tagcloud'

tags = [
  { :tag =&amp;gt; 'blog', :count =&amp;gt; 20 },
  { :tag =&amp;gt; 'ajax', :count =&amp;gt; 10 },
  { :tag =&amp;gt; 'mysql', :count  =&amp;gt; 5 },
  { :tag =&amp;gt; 'hatena', :count  =&amp;gt; 12 },
  { :tag =&amp;gt; 'bookmark', :count  =&amp;gt; 30 },
  { :tag =&amp;gt; 'rss', :count =&amp;gt; 1 },
  { :tag =&amp;gt; 'atom', :count =&amp;gt; 2 },
  { :tag =&amp;gt; 'misc', :count =&amp;gt; 10 },
  { :tag =&amp;gt; 'javascript', :count =&amp;gt; 11 },
  { :tag =&amp;gt; 'xml', :count =&amp;gt; 6 },
  { :tag =&amp;gt; 'perl', :count =&amp;gt; 32 },
]

cloud = TagCloud.new
tags.each do |t|
  cloud.add(t[:tag], "http://&amp;lt;your.domain&amp;gt;/#{t[:tag]}/", t[:count])
end
print cloud.html_and_css(20)
&lt;/pre&gt;

	&lt;p&gt;出力は以下のように、HTML::TagCloudと同じになります。&lt;/p&gt;


&lt;pre&gt;
&amp;lt;style&amp;gt;
span.tagcloud0 {font-size: 12px;}
span.tagcloud0 a {text-decoration: none;}
span.tagcloud1 {font-size: 13px;}
span.tagcloud1 a {text-decoration: none;}
span.tagcloud2 {font-size: 14px;}
span.tagcloud2 a {text-decoration: none;}
span.tagcloud3 {font-size: 15px;}
...
&amp;lt;/style&amp;gt;
&amp;lt;span class="tagcloud11"&amp;gt;&amp;lt;a href="http://&amp;lt;your.domain&amp;gt;/ajax/"&amp;gt;ajax&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span class="tagcloud2"&amp;gt;&amp;lt;a href="http://&amp;lt;your.domain&amp;gt;/atom/"&amp;gt;atom&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;span class="tagcloud17"&amp;gt;&amp;lt;a href="http://&amp;lt;your.domain&amp;gt;/blog/"&amp;gt;blog&amp;lt;/a&amp;gt;&amp;lt;/span&amp;gt;
...
&lt;/pre&gt;

	&lt;p&gt;さて、こいつを &lt;a href="http://lesserwiki.org/"&gt;LesserWiki&lt;/a&gt; に組み込もうか。&lt;/p&gt;</description>
      <pubDate>Fri, 05 Aug 2005 21:22:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:1c501cb209d203f1ad5d485204c68739</guid>
      <author>yatsu</author>
      <link>http://yatsu.info/articles/2005/08/05/ruby%E3%81%A7tagcloud-tagcloud-ruby</link>
      <category>Ruby</category>
      <category>Devel</category>
      <trackback:ping>http://yatsu.info/articles/trackback/20615</trackback:ping>
    </item>
  </channel>
</rss>
