JeffreyFrancesco.org 公開日 タグ Tag Permalink 現在地 Facebook page Twitter RSS feed

少し余裕が出来たので、久しぶりにこのサイトの構成を見直す作業を少しずつ進めております。

全体のマークアップや、レイアウト・デザイン関係もいくつかアイデアがあるので、徐々に変更していこうかと思っておりますが、まずはずっと気になってた部分の修正という事でぱぱっと。

立ち上げた当初からタグ関係の処理には tagging プラグインというのを使用しております。改造されたご本人がすでに 使用する事はオススメできません とおっしゃっているプラグインだったりするのですが、かといって一から作り直すのも面倒だし、自分の必要としていた機能はひと通り揃ってますし、特に動作自体にも問題ないですし、という事で意地になって使い続けております。

ただ、タグクラウド用のリストを作成してる部分、特にタグの使用頻度からレベルを計算している部分の計算方法だけは、あまり練られていないというか。もう元のコードは忘れてしまったのですが、概略だけをざっくりいえば単純に全てのタグの出現数をカウントして合算して、その合算数でタグ一つ一つの出現数を割った数字をレベル計算の元にしていてるのですね(分かりにくい説明で済みません)なのでタグが増えれば増えるほど、一番使用頻度の高いタグでもレベルが下がってしまって、頻度の低いタグとのレベル差がない状態になってしまい、結果としてはあまり「タグクラウド」と呼べるような状態ではないリストが出来上がってしまうという。

今までは、強引にその数値を何倍かして、使用頻度の高いタグが何とか最大レベルに近くなるようにしてごまかしておったのですが、今後さらにタグが増えた時の事を考えるとさすがにそのままじゃいかんだろう…という事で、じゃあどうすればいいのか、そもそも他のタグクラウド系のものはどうやって計算してるんだろう?と思って調べてみたら意外にあっさりと方法が見つかりましたので、その計算方法を組み込んでみました。

参考にしたのは、タグクラウドのサイズ計算【PHP】 - Programming Magic というエントリ。要は常に一番使用頻度が高いタグが1、一番使用頻度の低いタグが0となるようにして、各タグの頻度を0〜1の範囲で示すような数値を返せばいいという事ですね。

という訳で、プラグインの make_tagcloud サブルーチンの670行目辺り以下を次のように書き直してみました。まずは最大値と最小値の抜き出しから。

my @tag_values = map { $tags_data->{$_}->[1] } keys %$tags_data;

my $max = (sort { $b<=>$a } @tag_values)[0];
my $min = (sort { $a<=>$b } @tag_values)[0];

$tags_data というハッシュリファレンスに、各タグ名がキー・その URL とカウント数の配列が値として収まっているので、まずは map でカウント数を抜き出して配列 @tag_values に入れてやります。そこから最大値と最小値を抜き出すのはそれぞれ、この配列を降順および昇順で sort して先頭を取り出せばOK。

そこまで出来れば、あとは参考エントリにあるような計算をしてあげればOKであります。

if( scalar(keys %{ $tags_data }) > 0 ){

    my ( $diff, $sqrt_max, $sqrt_min ) = ( $max - $min, sqrt($max), sqrt($min) );
    my $sqrt_diff = $sqrt_max - $sqrt_min;

    foreach my $tag (sort keys %{ $tags_data }){
        my $tag_level;
        if ($diff == 0) {
            $tag_level = 3;
        } else {
            my $tag_count = sqrt( $tags_data->{$tag}->[1] );
            $tag_level = int( ($tag_count - $sqrt_min) / $sqrt_diff * 5 + 0.5 ) + 1;
        }
        $item .= $self->make_html(
            'name' => 'li',
            'text' => $self->make_html(
                'name' => 'a',
                'text' => $tag,
                'attr' => {
                    'href'  => $tags_data->{$tag}->[0],
                    'title' => "tag : $tag",
                },
            ),
            'attr' => {
                'class' => "level$tag_level",
            },
        ) . "\n";
    }
}

最初に必要な定数をざっと計算してそれぞれキープ。内容はそれぞれ、

  1. $diff は最大値と最小値の差
  2. $sqrt_max$sqrt_min はそれぞれ最大値と最小値の平方根値
  3. $sqrt_diff は 2. で出した平方根値の差

あとはそれぞれのタグについてカウント数に応じたレベルを割り出して、HTML コードを生成している部分です。最大値と最小値の差が0の場合はタグのレベル差がないという事なので $tag_level は単純に定数値3を取ってます(この場合の処理は別にしておかないと0で除算してエラーになる可能性が出てくるので必須です)それ以外の場合は0〜1を取った数値を5倍して四捨五入し、それに1を加える事で $tag_level が1〜6の範囲で整数を取る事になります。以降は元のコードとほぼ同じです。違う部分は foreach でループを回す時にキーを sort してアルファベット順に並ぶように変更してある位。

そんな感じで修正したのが現在のタグクラウドです。それ以外にもアルファベット順に並べたので ol ではなく ul で出力されるように変更したり、それに伴って CSS を一部修正したりはしてますが基本的には変わっていません。でも以前よりは各タグのレベルに差が付くようになって、ようやくタグクラウドと呼べるものに近付いたかなという感じですね。常にご覧になってないと分からないような差ですが。汗

まあ自分的には長年の悩みが解決したので、非常に満足しておりますです、ハイ。

という訳で、今さら Blosxom 関係のネタを書いたところで誰が参考にするんだとは思いますが、まあ書いておいたらいつか誰かの目に留まるだろうという事で。