0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【第21回】掲示板の「熱狂」を可視化する!独自計算式によるスレッド勢い(ikioi)ランキングTOP10とHOTバッジ

0
Posted at

「PV数でも総レス数でもない。今この瞬間、どこで『祭り』が起きているのかを秒速で可視化せよ」
令和に自作した2ちゃんねる風掲示板「つゔぁいちゃんねる(2ch.biz)」開発秘話の第21弾。第20回までで鉄壁のセキュリティと管理基盤を固めた開発陣は、ここから「掲示板を最高に盛り上げる攻めの機能開発」へと突入します。今回は、2chカルチャーの象徴である「勢い(ikioi)」アルゴリズムの実装と、トップページを彩るランキングUIの進化を公開します。


💡 はじめに:なぜ「PV数」ではなく「勢い」なのか?

一般的なブログやニュースサイトでは、人気記事をランキング化する指標として「ページビュー数(PV)」や「いいね数」が使われます。

しかし、2ちゃんねるの世界において、PV数はあまり意味を持ちません。
どれだけ過去に10万PV読まれたスレッドであっても、今誰も発言していなければそこは「終わった過疎スレ」です。逆に、まだ作られてから5分しか経っておらずPV数が少なくても、数十人が一斉に書き込んでいればそこは 「今まさに何かが起きている熱狂の中心地(祭り)」 です。

2ちゃんねらーが求めているのは、過去の累計値ではなく、 「今この瞬間、最も盛り上がっている場所はどこか」 というリアルタイムの熱量でした。

これを数値化する2ch独自の概念が 「勢い(ikioi)」 です。
開発初期(2026年8月21日)、全スレッドを横断してリアルタイムに勢いを計算し、トップページに掲出する 「いま熱いスレッド TOP 10」 を構築しました。


📐 「勢い(ikioi)」の算出アルゴリズム

「勢い」とは、 「そのスレッドが現在のペースのまま書き込まれ続けた場合、1日(24時間=86,400秒)で何レスに達するか」 を示す理論値です。

基本となる計算式は以下の通りです。

勢い = (現在の総レス数 - 1) / (現在時刻 - スレッド作成時刻 in 秒) * 86,400 (秒/日)

例えば:

  • 作成から 1時間(3,600秒) で 100レス ついたスレッド:
    $$\frac{99}{3600} \times 86400 \fallingdotseq 2,376$$
    → 勢い: 2,376 (非常に活発な人気スレ!)
  • 作成から 24時間(86,400秒) で 20レス ついたスレッド:
    $$\frac{19}{86400} \times 86400 \fallingdotseq 19$$
    → 勢い: 19 (まったり進行の過疎スレ)

このように、「総レス数」が少なくても、立ち上がったばかりで爆発的に伸びているスレッドがランキング上位に浮上します。


🛠️ バックエンドでの実装とエッジケース防御

サーバーサイドで全スレッドの勢いを計算してソートするAPIロジックです。

public function getTrendingThreads($limit = 10) {
    $now = time();

    // 1. アクティブなスレッド(dat落ちしていないスレッド)を抽出
    $stmt = $this->db->query("
        SELECT 
            t.id, t.board_id, t.title, t.created_at, t.updated_at,
            b.name AS board_name,
            (SELECT COUNT(*) FROM posts WHERE thread_id = t.id) AS post_count
        FROM threads t
        JOIN boards b ON t.board_id = b.id
        WHERE t.is_archived = 0
    ");
    $threads = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // 2. 各スレッドの勢いを計算
    foreach ($threads as &$th) {
        $createdTime = strtotime($th['created_at']);
        $elapsedSeconds = max(1, $now - $createdTime); // ⚠️ ゼロ除算防止(最低1秒)
        $effectivePosts = max(0, (int)$th['post_count'] - 1);

        // 勢い計算式
        $ikioi = ($effectivePosts / $elapsedSeconds) * 86400;
        $th['ikioi'] = round($ikioi);
    }
    unset($th);

    // 3. 勢いの降順でソート
    usort($threads, function($a, $b) {
        return $b['ikioi'] <=> $a['ikioi'];
    });

    // 4. 指定件数(TOP 10)を返却
    return array_slice($threads, 0, $limit);
}

工夫したポイント:ゼロ除算クラッシュの防止

スレッドが作成された「0秒後」にAPIが叩かれると、$now - $createdTime = 0 となり、ゼロ除算(Division by Zero)エラーでサーバーが落ちます。
max(1, $now - $createdTime) とすることで、経過秒数が最低でも1秒になるよう安全ガードを敷いています。


🎨 TOP 5 から TOP 10 へ!レスポンシブ2列グリッドUIの進化

当初はトップページに「TOP 5」を縦並びで表示していましたが、掲示板が盛り上がってくると「5件じゃ少なすぎる!もっとたくさんの話題を一覧したい」という要望が出ました。

そこで、掲載件数を TOP 10 へと一挙倍増 させ、画面をコンパクトかつ美しく保つために CSS Grid によるレスポンシブ2列レイアウト を導入しました。

<!-- index.html の勢いランキング骨格 -->
<section class="hot-threads-section">
    <div class="section-header">
        <h2>🔥 いま熱いスレッド TOP 10</h2>
        <span class="refresh-indicator">リアルタイム集計中</span>
    </div>
    <div id="hot-threads-grid" class="hot-threads-grid">
        <!-- app.js が10枚のカードを自動レンダリング -->
    </div>
</section>
/* style.css */
.hot-threads-grid {
    display: grid;
    /* PC/タブレット: 横幅340px以上あれば自動で2列にタイリング */
    grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
    gap: 12px;
    margin-top: 12px;
}

/* スマホ表示時は自動的に1列に折り返される */
@media (max-width: 768px) {
    .hot-threads-grid {
        grid-template-columns: 1fr;
    }
}

🏆 視覚を刺激する「順位バッジ」と「🔥 HOTバッジ」

ランキングである以上、一目で順位と熱量が分からなければ面白くありません。

/* 順位バッジのプレミアムグラデーション */
.rank-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    font-weight: bold;
    font-size: 0.85rem;
    color: #fff;
}

.rank-1 { background: linear-gradient(135deg, #ffd700, #ff8c00); } /* 🥇 金 */
.rank-2 { background: linear-gradient(135deg, #e0e0e0, #9e9e9e); } /* 🥈 銀 */
.rank-3 { background: linear-gradient(135deg, #cd7f32, #8b4513); } /* 🥉 銅 */
.rank-other { background: #6c757d; }

/* 勢い1000超えのHOTバッジ */
.hot-tag {
    background-color: #ff4500;
    color: white;
    padding: 2px 6px;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: bold;
    animation: pulse 1.5s infinite; /* 鼓動するアニメーション */
}

@keyframes pulse {
    0% { transform: scale(1); }
    50% { transform: scale(1.05); }
    100% { transform: scale(1); }
}

カード内には、スレッドタイトルだけでなく所属する「板名」、現在の「総レス数」、そしてオレンジ色に輝く「勢い: 2,450」が掲出されます。
1位〜3位のメダルカラーと、鼓動するHOTバッジが、ユーザーに 「今すぐこのスレを覗いてみたい!」 という強い衝動を与えます。


🎯 まとめと次回予告

第21回となる今回は、掲示板の熱狂を数値とビジュアルで表現する 「スレッド勢い(ikioi)ランキングTOP 10」 について解説しました。

今回の学び・ポイント

  • 累計ではなく「瞬間風速」を追え :コミュニティの活性化には、今人が集まっている場所をリアルタイムで示すことが最も効果的。
  • ゼロ除算対策と境界値の安全設計 :数学的な計算式をWebアプリに組み込む際の基本動作。
  • CSS Gridによる情報の高密度化 :画面幅に応じて1列から2列へ自然に流れるカードレイアウトが、探索体験を劇的に向上させる。

勢いランキングによって、人気スレッドへの導線は完璧になりました。
しかし、ランキングだけでは、まだ生まれたばかりの「新着スレッド」が埋もれてしまいます。
「カテゴリごとの新着スレッドを、見落とさずに一目でチェックできる高密度ヘッドライン」 が必要です。

次回、 【第22回】タイムラインを見逃すな!カテゴリ別新着スレッド高密度ヘッドライン表示 へと続きます!


🔗 関連リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?