Chart.jsでレーダーチャートを作る際、標準のラベル表示機能では日本語・英語の複数行表示やスタイル指定に限界があります。
そこで本記事では、ラベルをChart.jsのCanvas外にHTMLとして自由に配置し、デザインの自由度とSEO対応を両立する実装方法を紹介します。
なぜChart.jsのラベルをHTMLで出力するのか?
Chart.jsはCanvasベースの描画ライブラリであり、ラベル(pointLabels)はCanvas内に直接描画されるため、以下のような制限があります。
- 日本語と英語を行分けで表示できない
- フォントや色などのスタイル指定が困難
これを解決するために、「ラベル部分だけHTMLで出力し、Canvasの外側に自由に配置」する方法を採用します。
実装イメージ
- Canvas中央にChart.jsのレーダーチャートを表示
- 6つの項目ラベルをCanvasの外にHTMLで配置
- ラベルはACF(Advanced Custom Fields)で日本語+英語を管理
- BEM命名規則でクラスを統一し、スタイル制御を明確化
実装手順
1. ACFで6項目のラベルと数値を用意
ACF無料版でも以下のようにグループで構成可能です。
フィールド名 | 内容 |
---|---|
chart_1 ~ 6 | グループ |
└ label_ja | 日本語ラベル |
└ label_en | 英語ラベル |
└ value | 値:範囲(0〜100) |
manager_color | チャートの色:カラーピッカー(16進値文字列) |
ACF画面のスクショも貼っておきます。


私は、カスタムタクソノミーに設定しています。
管理画面ではこのように表示されます。

2. JavaScriptとHTMLとPHPでラベルを出力
2-1. JavaScriptライブラリ(headタグなどに埋め込み)
Chart.jsを読み込みます。
この後のコードより先に読み込ませる必要があるため、headタグ内に書いた方がいいと思います。
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
2-2. JavaScriptとHTMLとPHP(bodyタグ内に埋め込み)
次のコードをbodyタグ内に埋め込みます。
JavaScriptとHTMLとPHPが混在していますが、この順番ではないとうまく出力されません。
構成は以下のようになっています。
- 【PHP】ACFに入っている値を取得
- 【JavaScript】PHPからJavaScriptにデータを渡す
- 【HTML,PHP】チャートの出力コードを書く
- 【JavaScript】チャートの出力コードを書く
<?php
// 1. ACFに入っている値を取得----
$charts = [];
for ($i = 1; $i <= 6; $i++) {
$group = get_field("chart_$i"); // チャートのグループフィールドを取得
$label_ja = $group['label_ja'] ?? ''; // 日本語ラベル
$label_en = $group['label_en'] ?? ''; // 英語ラベル
$value = $group['value'] ?? 0; // チャートの値
$charts[] = [
'label_ja' => $label_ja,
'label_en' => $label_en,
'value' => $value
];
}
$values = array_column($charts, 'value'); // チャートの値を配列に格納
$color = get_field('manager_color'); // 色を取得
?>
<script>
// 2.PHPからJavaScriptにデータを渡す----
const chartData = {
values: <?php echo json_encode(array_column($charts, 'value')); ?>,
color: <?php echo json_encode(get_field('manager_color')); ?>
};
</script>
<!-- 3.チャートの出力コード -->
<div class="p-radarChart">
<?php foreach ($charts as $index => $item): ?>
<div class="p-radarChart__label p-radarChart__label--<?php echo $index; ?>">
<span class="en"><?php echo esc_html($item['label_en']); ?></span>
<strong class="ja"><?php echo esc_html($item['label_ja']); ?></strong>
</div>
<?php endforeach; ?>
<canvas id="p-radarChart__canvas" class="p-radarChart__canvas" width="400" height="400"></canvas>
</div>
<script>
// 4.チャートの出力コード----
// HEX → RGBA変換関数(背景に透明度をつけるため)
function hexToRgba(hex, alpha = 1) {
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}
// チャート初期化
const ctx = document.getElementById('p-radarChart__canvas').getContext('2d');
new Chart(ctx, {
type: 'radar',
data: {
labels: ['', '', '', '', '', ''], // Canvas内のラベルは非表示
datasets: [{
label: 'Player Stats',
data: chartData.values,
fill: true,
backgroundColor: hexToRgba(chartData.color, 0.6), // 60%透明
borderColor: chartData.color, // 枠線の色
pointBackgroundColor: 'transparent', //頂点の色
borderWidth: 0, // 枠線の太さ
}]
},
options: {
responsive: false,
scales: {
r: {
min: 0,
max: 100,
pointLabels: {
display: false
},
ticks: {
display: false
},
grid: {
color: '#ccc'
},
angleLines: {
color: '#ccc'
}
}
},
plugins: {
legend: {
display: false
}
}
}
});
</script>
2-3. SCSSで装飾
/*レーダーチャート--------*/
.p-radarChart {
position: relative;
width: 400px;
height: 400px;
margin: 0 auto;
&__canvas {
width: 100%;
height: 100%;
display: block;
}
&__label {
position: absolute;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
text-align: left;
font-size: 14px;
line-height: 1.4;
color: #333;
transform: translate(-50%, -50%);
white-space: nowrap; /* 改行を防止 */
pointer-events: none;
.en {
display: block;
color: #666;
font-size: 12px;
text-transform: uppercase; // 英語のテキストを大文字に変換
}
.ja {
display: block;
font-size: 14px;
}
/* ラベル配置 */
&--0 {
top: -5%;
left: 50%;
}
&--1 {
top: 21%;
left: 100%;
}
&--2 {
top: 78%;
left: 100%;
}
&--3 {
top: 105%;
left: 50%;
}
&--4 {
top: 78%;
left: 0%;
}
&--5 {
top: 21%;
left: 0%;
}
}
}