この記事でできること
- SVGパスにD3.jsでデータをバインドして色分け・クリックイベントを実装する
- WordPress(SWELL)上でD3.js v7を
<script src>なしで安全にロードする - フィルタ変更時に地図・テーブル・チャートを同時更新するデータフローを組む
- スマホのtouchstartで「開いて即閉じ」バグを防ぐ方法を知る
完成形は日本自治体AI政策データベース(ai-japan-index.com)で動作確認できる。
環境・前提
- D3.js: v7.9.0(CDN動的ロード)
- ブラウザ: Chrome 133 / Safari 18 / Firefox 135 で動作確認
- WordPress: 6.7.x + SWELLテーマ 2.11.x
- デプロイ形式:
<!-- wp:html -->ブロック(インラインHTML) - 外部ライブラリ: D3.jsのみ(他不使用)
- Node.js/ビルドツール: 不使用(静的HTMLのみ)
完成形
47都道府県のクリッカブルSVGマップ、政策比較テーブル、D3.jsチャート3種を組み合わせたインタラクティブツール。都道府県をクリックすると政策詳細が表示され、地域/分野/ステータス/年のフィルタで絞り込みができる。
Step 1: D3.jsをWordPressで安全にロードする
WordPressのコンテンツ内に <script src="CDN"> を書いても、SWELLテーマが無視してロードされない。動的ロードが必須。
NG(SWELLで動作しない):
<script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>
OK(動的ロード):
function loadD3ThenInit() {
// 既にロード済みの場合はスキップ
if (typeof d3 !== "undefined") {
initAll();
return;
}
const s = document.createElement("script");
s.src = "https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js";
s.onload = function() { initAll(); };
s.onerror = function() {
document.getElementById("map-root").textContent =
"グラフの読み込みに失敗しました。ページを再読み込みしてください。";
};
document.head.appendChild(s);
}
document.addEventListener("DOMContentLoaded", loadD3ThenInit);
typeof d3チェックで二重ロードを防ぎ、onerrorでフォールバックメッセージを表示する。この2点が実務上重要。
Step 2: SVGパスにデータをバインドして色分けする
都道府県パスにはJIS X 0401の2桁コード(01=北海道、13=東京都など)をdata-code属性で付与しておく。
<!-- japan-map.svg の各パス -->
<path class="prefecture-path" data-code="13" data-name="東京都" d="M..."/>
<path class="prefecture-path" data-code="27" data-name="大阪府" d="M..."/>
D3.jsでパス全体を一括更新:
const statusColorMap = {
deployed: "#2d9e6b", // 導入済み
pilot: "#f0a500", // 実証中
planned: "#6b7fd4", // 計画中
unknown: "#c8c8c8" // 不明
};
function renderMap(filteredData) {
// prefectureCodeをキーにしたMapで高速ルックアップ
const statusByCode = new Map(
filteredData.map(d => [d.prefectureCode, d.aiAdoptionStatus])
);
d3.selectAll(".prefecture-path")
.attr("fill", function() {
const code = this.getAttribute("data-code");
return statusColorMap[statusByCode.get(code)] || statusColorMap.unknown;
})
.on("click", function(event) {
event.stopPropagation(); // バブリング防止
const code = this.getAttribute("data-code");
showPrefectureDetail(code);
});
}
d3.selectAllで47パスを一括処理するのがポイント。forEachループよりもD3のバインディングの方がDOM操作がバッチ化されて効率的。
Step 3: フィルタ→3ビュー同期更新
フィルタはAND条件で1関数に集約し、地図・テーブル・チャートを同時更新する。
重要: &&演算子はWordPressが&&に変換してJSを壊す。
NG(WordPressで動作しない):
// これはWordPressが && に変換してSyntaxErrorになる
return regionOk && categoryOk && statusOk;
OK(三項演算子またはネストifで回避):
function applyFilters() {
const filtered = policyData.localPolicies.filter(function(policy) {
const regionOk = !activeFilters.region
? true
: getRegion(policy.prefectureCode) === activeFilters.region;
const categoryOk = !activeFilters.category
? true
: policy.category === activeFilters.category;
const statusOk = !activeFilters.status
? true
: policy.aiAdoptionStatus === activeFilters.status;
// ネストifでAND条件を表現(&&を使わない)
if (!regionOk) return false;
if (!categoryOk) return false;
if (!statusOk) return false;
return true;
});
// 3ビューを同時更新
renderMap(filtered);
renderTable(filtered);
renderCharts(filtered);
}
フィルタボタンのクリック:
document.querySelectorAll(".filter-btn").forEach(function(btn) {
btn.addEventListener("click", function() {
const key = this.dataset.filterKey;
const val = this.dataset.filterValue;
// トグル(同じ値を再クリックで解除)
activeFilters[key] = activeFilters[key] === val ? null : val;
applyFilters();
});
});
Step 4: スマホ向け下部固定パネル
スマホではツールチップではなく画面下部固定パネルで詳細を表示する。マウス追従型はスマホで画面外にはみ出す。
function showPrefectureDetail(code) {
const prefecture = getPrefectureData(code);
if (!prefecture) return;
// スマホ判定(767px以下)
const isMobile = window.innerWidth <= 767;
if (isMobile) {
// 下部固定パネルに表示
const panel = document.getElementById("mobile-detail-panel");
panel.innerHTML = buildDetailHTML(prefecture);
panel.style.display = "block";
// パネル外タップで閉じる
document.addEventListener("touchstart", closePanelOnOutsideTap, { once: true });
} else {
// PCはツールチップ
showTooltip(prefecture);
}
}
function closePanelOnOutsideTap(e) {
const panel = document.getElementById("mobile-detail-panel");
if (!panel.contains(e.target)) {
panel.style.display = "none";
}
}
パネルのCSS:
#mobile-detail-panel {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background: #1a1a2e;
border-top: 2px solid #ff8906;
max-height: 40vh;
overflow-y: auto;
z-index: 10000;
padding: 16px;
display: none;
}
Step 5: 動作確認
ブラウザの開発者ツールで以下を確認する:
-
コンソールエラーがないか: D3.jsロード失敗・
&変換によるSyntaxErrorが最多 - 地図が色分けされるか: 「導入済み(緑)」が表示される都道府県をクリックして詳細が出るか
- フィルタが機能するか: 「ステータス: 実証中」フィルタで地図・テーブルが連動して変わるか
- スマホ表示: Chrome DevToolsのモバイルエミュレータで767px以下のレイアウトを確認
// デバッグ用: D3.jsが正しくロードされているか確認
console.log("D3 version:", d3.version); // "7.x.x" が出れば正常
つまずきポイントまとめ
-
D3.jsがロードされない:
<script src>→ 動的ロードに変更。typeof d3チェックで確認 -
&&演算子でSyntaxError: WordPressが&&に変換する。三項演算子かネストifで回避 -
スマホでパネルが「開いて即閉じ」: touchstartの
stopPropagation()漏れ。パスのタッチハンドラに必ずセットで書く -
SVGのインライン
<style>がページ全体に漏れる:DOMParserでSVGを取得後、<style>要素を削除してから挿入 -
フィルタ後に地図色が残る:
renderMap内で全パスをいったんグレーにリセットしてから再描画する -
chart.destroyが必要な場面: D3.jsは
svg.selectAll("*").remove()でクリアするか、svgごと再生成する
まとめ
- D3.js v7のWordPressロードは動的ブートストラップ必須(
<script src>不可) -
&&演算子はWordPressで必ず壊れる。三項演算子(? :)かネストifに置き換える - スマホのtouchstartには
e.stopPropagation()を必ずセットで書く - フィルタは1関数に集約し、地図・テーブル・チャートを同時更新する設計が保守しやすい
- SVG外部ファイルを動的挿入する際はインラインstyleの漏れに注意
完成したツールはこちら(AI Japan Index - 日本自治体AI政策データベース)
FAQ(手順・エラー対処視点)
Q1. SVGパスのdata-code属性はどこから取得すればよいですか?
JIS X 0401の都道府県コード(01〜47)を使う。GitHubで公開されているフリーのjapan-svgファイルはdata-codeやid属性を持つものが多い。持っていない場合は、<path>要素に手動で追加するか、Pythonスクリプトで一括付与できる(xml.etree.ElementTree使用)。
Q2. フィルタを追加するにはdata.jsのどこを変更しますか?
フィルタキーはpolicyData.localPoliciesの各オブジェクトのプロパティ名に対応している。新しいフィルタ(例: 「予算規模」)を追加する場合は、各エントリにbudgetRange: "large"等のフィールドを追加し、applyFilters()内にbudgetOkの判定を追加するだけで済む。
Q3. 「グラフの読み込みに失敗しました」と表示されたときの対処法は?
CDN(cdn.jsdelivr.net)へのアクセスがブロックされている可能性がある。ネットワークタブでd3.min.jsのリクエストを確認する。企業プロキシ環境ではunpkg.comやcdnjs.cloudflare.comのURLに変更すると解決する場合がある。
Q4. 地図の都道府県が全てグレーのまま色が変わらない場合はどうしますか?
SVGパスにdata-code属性がない、またはpolicyData.localPoliciesのprefectureCodeと一致していない可能性がある。console.log(statusByCode)で変換後のMapを確認し、d3.selectAll(".prefecture-path").size()で選択されたパス数を確認する。0が返る場合はクラス名のタイポを疑う。
データ出典: 総務省 自治体AI・RPA実証実験・導入状況等調査(2024年12月31日現在)/ 2026年3月時点の情報
