標籤雲 視覺化呈現標籤熱門度,字體大小對應出現頻率。本文提供一個彈性、可重用的 getTagCloud() 函式,支援自訂最小/最大字體、HTML 屬性、排序方式,並示範整合資料庫查詢的完整流程。
<?php
/**
* 產生標籤雲 HTML
*
* @param array $tags 關聯陣列 [標籤名稱 => 權重/次數]
* @param int $minFontSize 最小字體 (px)
* @param int $maxFontSize 最大字體 (px)
* @param string $urlPattern 連結 URL 模式,含 {tag} 佔位符
* @param array $attributes 額外 屬性 ['class' => 'tag', 'rel' => 'tag']
* @param string $sort 排序:'name' (字母), 'weight' (權重), 'random'
* @return string HTML 字串
*/
function getTagCloud(
array $tags,
int $minFontSize = 12,
int $maxFontSize = 30,
string $urlPattern = '/tag/{tag}',
array $attributes = [],
string $sort = 'name'
): string {
if (empty($tags)) {
return '<div class="tag-cloud"></div>';
}
// 1. 排序
switch ($sort) {
case 'weight':
arsort($tags); // 權重大到小
break;
case 'random':
uksort($tags, fn() => rand(-1, 1));
break;
case 'name':
default:
ksort($tags); // 字母順序
break;
}
// 2. 計算權重範圍
$minCount = min($tags);
$maxCount = max($tags);
$spread = $maxCount - $minCount;
if ($spread === 0) {
$spread = 1; // 避免除以零
}
$fontRange = $maxFontSize - $minFontSize;
// 3. 預設屬性
$defaultAttr = ['class' => 'tag-cloud-item', 'rel' => 'tag'];
$attr = array_merge($defaultAttr, $attributes);
$attrStr = '';
foreach ($attr as $k => $v) {
$attrStr .= ' ' . $k . '="' . htmlspecialchars($v) . '"';
}
// 4. 產生項目
$items = [];
foreach ($tags as $tag => $count) {
// 線性插值計算字體大小
$size = $minFontSize + (($count - $minCount) / $spread) * $fontRange;
$size = round($size, 1);
$url = str_replace('{tag}', urlencode($tag), $urlPattern);
$tagHtml = htmlspecialchars($tag);
$items[] = "<a href=\"{$url}\" style=\"font-size: {$size}px;\"{$attrStr}>{$tagHtml}</a>";
}
return '<div class="tag-cloud">' . implode(' ', $items) . '</div>';
}
<?php
// 模擬資料:標籤 => 文章數
$tags = [
'PHP' => 120,
'Laravel' => 85,
'JavaScript' => 95,
'Vue' => 60,
'Docker' => 40,
'MySQL' => 70,
'Redis' => 30,
'API' => 55,
];
// 直接輸出
echo getTagCloud($tags, 14, 32, '/blog/tag/{tag}', ['class' => 'tag-link'], 'weight');
<?php
function getTagsFromDatabase(PDO $pdo, int $limit = 50): array {
$sql = "
SELECT t.name, COUNT(pt.post_id) AS cnt
FROM tags t
JOIN post_tags pt ON t.id = pt.tag_id
JOIN posts p ON pt.post_id = p.id
WHERE p.status = 'published'
GROUP BY t.id
ORDER BY cnt DESC
LIMIT :limit
";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->execute();
$tags = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$tags[$row['name']] = (int)$row['cnt'];
}
return $tags;
}
// 使用
$tags = getTagsFromDatabase($pdo, 100);
echo getTagCloud($tags, 12, 28, '/search?q={tag}', ['class' => 'tag'], 'weight');
.tag-cloud {
line-height: 2.5;
text-align: center;
padding: 20px;
}
.tag-cloud-item {
display: inline-block;
margin: 0 6px 10px;
text-decoration: none;
color: #333;
transition: color 0.2s, transform 0.2s;
}
.tag-cloud-item:hover {
color: #007bff;
transform: scale(1.1);
text-decoration: underline;
}
/* 響應式字體上限 */
@media (max-width: 480px) {
.tag-cloud-item {
max-font-size: 24px; /* 需配合 inline style 覆蓋 */
}
}
若少數標籤極高頻、大多數極低頻,線性縮放會導致大多數標籤字體過小。改用對數縮放:
// 在函式內替換線性插值部分:
$logMin = log($minCount + 1);
$logMax = log($maxCount + 1);
$logVal = log($count + 1);
$ratio = ($logMax - $logMin) > 0 ? ($logVal - $logMin) / ($logMax - $logMin) : 0.5;
$size = $minFontSize + $ratio * $fontRange;
rel="tag" 符合 Microformats 標準getTagCloud() 以線性/對數插值將權重映射為字體大小,支援自訂 URL、排序、屬性,易於整合既有專案。搭配資料庫彙總查詢與適當 CSS,即可打造美觀、無障礙、SEO 友善的標籤雲元件。