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?

『AIリスキリング適性診断 2026』WordPressでD3.jsのレーダーチャートを表示しようとして3回失敗した話

0
Posted at

ai-reskilling-check.jpg

この記事でできること

  • D3.js v7でレーダーチャート(蜘蛛の巣グラフ)を作れる
  • WordPressにD3.jsチャートを埋め込むときの「ありがちな罠」を回避できる
  • 8問のステップフォームをVanilla JSで実装できる
  • 実際に動作するツールは AIリスキリング適性診断 2026 で確認できる

環境・前提

  • ブラウザ: モダンブラウザ(Chrome/Firefox/Safari の最新版)
  • ライブラリ: D3.js v7(CDNから動的ロード)
  • CMS: WordPress(SWELLテーマ)— <!-- wp:html -->ブロック内に全コード
  • 言語: Vanilla JS(ES2020)+ HTML + CSS
  • 追加依存関係: なし(ビルドプロセスなし)

完成形

8問に答えると、こんなものが表示される。

  • 円弧型ゲージ(0〜100点のスコア)
  • 6軸のレーダーチャート(AIリテラシー・デジタルスキル・ビジネス・コミュ・専門性・学習意欲)
  • 診断タイプ(5種類)
  • 優先リスキリングTOP3 + おすすめ学習リソースのリンク

AIリスキリング適性診断 2026 — 実際に動くやつ


手順

Step 1: D3.jsをWordPressに読み込む

NG例(WordPressでは動かない):

<script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>

WordPressのSWELLテーマは、投稿コンテンツ内の<script src="...">タグを無視する。外部スクリプトは読み込まれない。

OK例(動的ロードパターン):

function loadD3(callback) {
  if (typeof d3 !== 'undefined') {
    callback();
    return;
  }
  var s = document.createElement('script');
  s.src = 'https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js';
  s.onload = callback;
  document.head.appendChild(s);
}

loadD3(function() {
  initDiagnostic(); // D3が読み込まれてから初期化
});

typeof d3でロード済みかチェック → 未ロードならcreateElement('script')で動的に読み込む → onloadで初期化関数を呼ぶ。このパターンだとWordPressでもD3.jsが使える。

つまずきポイント: onloadの前にinitDiagnostic()を呼んでしまい、「d3 is not defined」エラーが出た。非同期処理の順番の問題。

Step 2: &&演算子を使わない

NG例(WordPressがJSを壊す):

if (answers.q4 === 'daily' && answers.q1 === 'engineer') {
  score += 2;
}

WordPressのコンテンツフィルターが&&&#038;&#038;(HTMLエンティティ)に変換する。これで構文エラーになり、スクリプト全体が止まる。

OK例(ネストifに変換する):

if (answers.q4 === 'daily') {
  if (answers.q1 === 'engineer') {
    score += 2;
  }
}

||も同様の問題が起きる場合がある。三項演算子a ? b : cか、ネストifに書き直すのが安全。

つまずきポイント: 最初は「なぜ動かないの?」とずっとD3.jsを疑っていた。実際の原因は&&だったので、DevToolsのConsoleでエラーメッセージを確認するのが最初のステップ。

Step 3: ステップフォームの状態を正しく持つ

8問を1問ずつ表示するステップフォームを作るとき、「戻る」ボタンで前の回答を保持するには状態管理が必要だ。

NG例(ステップ番号だけ管理):

let currentStep = 0;

function goBack() {
  currentStep--;
  renderStep(currentStep); // 回答が消える
}

OK例(回答も一緒に持つ):

var state = {
  step: 0,
  answers: {}
};

function selectAnswer(questionKey, value) {
  state.answers[questionKey] = value; // 回答を保存
}

function goBack() {
  state.step--;
  renderStep(state.step, state.answers); // 保存済み回答を渡す
}

function renderStep(stepNum, savedAnswers) {
  // savedAnswersに回答があればラジオボタンをchecked状態で描画
  var saved = savedAnswers['q' + (stepNum + 1)];
  if (saved) {
    var radio = document.querySelector('input[value="' + saved + '"]');
    if (radio) radio.checked = true;
  }
}

ポイント: 状態をvar state = { step, answers }という1つのオブジェクトにまとめておくと、どこからでも参照しやすい。

Step 4: レーダーチャートを描く

D3.jsでレーダーチャートを描くには、「各軸の角度と値から座標を計算してpolygonで結ぶ」のが基本だ。

var axes = ['aiLiteracy', 'digital', 'business', 'communication', 'expertise', 'adaptability'];
var maxValue = 20; // 各軸の最大値
var cx = innerW / 2;
var cy = innerH / 2;
var innerR = Math.min(cx, cy) - 20;
var angleStep = (2 * Math.PI) / axes.length;

// 各軸の先端座標を計算
function getCoord(axisIndex, value) {
  var angle = axisIndex * angleStep - Math.PI / 2; // 12時スタート
  var r = (value / maxValue) * innerR;
  return {
    x: cx + r * Math.cos(angle),
    y: cy + r * Math.sin(angle)
  };
}

// スコアのポリゴン(塗り面)を描画
var points = axes.map(function(key, i) {
  var coord = getCoord(i, scores[key]);
  return coord.x + ',' + coord.y;
}).join(' ');

svg.append('polygon')
  .attr('points', points)
  .attr('fill', 'rgba(var(--aji-accent-rgb), 0.2)')
  .attr('stroke', 'var(--aji-accent)')
  .attr('stroke-width', 2);

つまずきポイント: - Math.PI / 2を忘れると12時方向ではなく3時方向スタートになる。最初の軸が右側に来てレイアウトがおかしくなった。

Step 5: 軸ラベルはHTML divで配置する

SVG <text>でラベルを書くとスマホで文字が切れる。「コミュニケーション」「専門性深度」は7〜8文字あり、SVG textは自動改行しないからだ。

NG例(SVG textでラベル):

svg.append('text')
  .attr('x', labelX)
  .attr('y', labelY)
  .text('コミュニケーション'); // スマホ幅で確実に切れる

OK例(HTML divをposition:absoluteで配置):

.radar-wrap {
  position: relative; /* これが必要 */
}
.radar-label {
  position: absolute;
  font-size: 12px;
  color: #a7a9be;
  max-width: 90px;
  word-break: keep-all;
  overflow-wrap: break-word;
  text-align: center;
  transform: translate(-50%, -50%); /* 中央揃え */
}
var label = document.createElement('div');
label.className = 'radar-label';
label.style.left = labelX + 'px';
label.style.top = labelY + 'px';
// スマホでは短縮形を使う
var isMobile = window.innerWidth <= 767;
var shortNames = {
  'AIリテラシー': 'AIリテ',
  'コミュニケーション': 'コミュ',
  '専門性深度': '専門性',
  '学習適応力': '学習力'
};
label.textContent = isMobile ? (shortNames[axisName] || axisName) : axisName;
chartContainer.appendChild(label);

Step 6: スマホのツールチップは下部固定パネルにする

スマホでバーやポイントをタップしたとき、マウス追従型のツールチップは画面外に出てしまって読めない。

OK例(画面下部固定パネル):

.mobile-panel {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  background: #1a1a2e;
  border-top: 2px solid var(--aji-accent);
  padding: 16px;
  max-height: 40vh;
  overflow-y: auto;
  z-index: 10000;
  display: none; /* 最初は非表示 */
}
element.addEventListener('touchstart', function(e) {
  e.preventDefault();
  e.stopPropagation(); // これがないと「パネル外タップ」と誤判定される
  var panel = document.querySelector('.mobile-panel');
  panel.innerHTML = '<strong>' + d.name + '</strong>: ' + d.value + '';
  panel.style.display = 'block';
});

// パネル外タップで閉じる
document.addEventListener('touchstart', function() {
  var panel = document.querySelector('.mobile-panel');
  if (panel) panel.style.display = 'none';
});

つまずきポイント: e.stopPropagation()を忘れると、要素タップ→パネル表示→即座に「パネル外タップ」と判定→パネルが消える、という謎の動作になる。


つまずきポイントまとめ

  • <script src="CDN">が動かない: WordPressはコンテンツ内の外部スクリプトタグを無視する。動的ロードパターンを使う
  • &&でJSエラー: WordPressのフィルターが&#038;&#038;に変換する。ネストifか三項演算子に書き直す
  • 戻るボタンで回答が消える: 状態管理に回答も含める。state.answersに蓄積する
  • 軸ラベルがスマホで切れる: SVG textではなくHTML divをposition: absoluteで配置する。word-break: keep-allを忘れずに
  • タップしてもパネルがすぐ消える: e.stopPropagation()が必要。イベントバブリングを止めないとdocumentのtouchstartハンドラが反応する
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?