カスタムツールチップによるインタラクティブなデータ可視化の構築
chart.xkcdは、手描き風のグラフを簡単に作成できるライブラリです。その中でもツールチップはユーザーとデータをつなぐ重要なインターフェースであり、デフォルトの表示では限界があります。この記事では、src/components/Tooltip.js をカスタマイズすることで、独自のスタイルと動作を持つツールチップを実現する方法を解説します。
ツールチップの基本構造
ツールチップは Tooltip クラスとして定義されており、コンストラクタで親要素、タイトル、データ項目、位置情報などを受け取ります。内部ではSVG要素を使って背景矩形とテキストを描画し、動的にサイズや位置を調整します。
constructor({
parent,
title,
items,
position,
unxkcdify,
backgroundColor,
strokeColor,
}) {
this.title = title;
this.items = items;
this.position = position;
// SVGコンテナの作成
this.svg = parent.append('svg')
.attr('x', this._getUpLeftX())
.attr('y', this._getUpLeftY())
.style('visibility', 'hidden');
// 背景矩形の生成
this.tipBackground = this.svg.append('rect')
.style('fill', backgroundColor)
.attr('fill-opacity', 0.9)
.attr('stroke', strokeColor)
.attr('stroke-width', 2)
.attr('rx', 5)
.attr('ry', 5);
}
_getBackgroundWidth() と _getBackgroundHeight() によってコンテンツに応じたサイズが自動計算され、_getUpLeftX() / _getUpLeftY() により上左、上右、下左、下右の4パターンに対応した位置指定が可能になります。
スタイルのカスタマイズ
背景と枠線の設定
背景色や枠線の太さ、角の丸みはコンストラクタ引数で直接変更できます。例えば、青系の背景に白い枠線を適用するには以下のように記述します。
const customTooltip = new Tooltip({
parent: chart.svg,
title: "売上推移",
items: [{ color: "#3498db", text: "1月: ¥12,500" }],
position: { type: "upRight", x: 150, y: 80 },
backgroundColor: "#3498db",
strokeColor: "#ffffff"
});
また、rx, ry, stroke-width の値を編集することで、より柔らかい印象や強調されたデザインも可能です。
this.tipBackground
.attr('rx', 10)
.attr('ry', 10)
.attr('stroke-width', 3);
テキストスタイルの改善
タイトルと各項目のテキストは、font-size, font-weight, fill などのプロパティでカスタマイズできます。統一感のある見た目にするために、テーマカラーに合わせて調整しましょう。
this.tipTitle = this.svg.append('text')
.style('font-size', 14)
.style('font-weight', 'bold')
.style('fill', '#1a5f7a');
インタラクションの強化
動的更新機能
update() メソッドを使用すると、データの変化に応じてツールチップの内容を再描画できます。これはリアルタイム監視やマウス追跡などに適しています。
// 初期化
const tooltip = new Tooltip({ /* 設定 */ });
// 更新
tooltip.update({
title: "現在の気温",
items: [{ color: "#e74c3c", text: `${currentTemp}°C` }],
position: { type: "upLeft", x: event.pageX, y: event.pageY }
});
このメソッドは内容の変更がある場合のみ再描画を行い、無駄なレンダリングを回避します。
表示制御
show() と hide() メソッドを使って、明示的にツールチップの表示・非表示を制御できます。これにより、マウスオーバー時の反応を自由に設計できます。
chart.svg.selectAll(".dot")
.on("mouseover", function(event) {
tooltip.show();
})
.on("mouseout", function() {
tooltip.hide();
})
.on("mousemove", function(event) {
tooltip.update({
position: { type: "upRight", x: event.pageX, y: event.pageY }
});
});
高度なカスタマイズ技術
レイアウトの再設計
既存の「色ブロック + テキスト」の水平レイアウトを変更したい場合、_generateTipItem() メソッドのロジックを修正します。複数列や右側に数値を配置するような構成も可能になります。
_generateTipItem(item, index) {
const itemSvg = this.svg.append('svg')
.attr('x', 15)
.attr('y', 30 + index * 25);
// 色のアイコン
itemSvg.append('rect')
.attr('width', 12)
.attr('height', 12)
.attr('fill', item.color);
// 主要テキスト
itemSvg.append('text')
.attr('x', 25)
.attr('y', 12)
.text(item.label);
// 右端に数値を表示
itemSvg.append('text')
.attr('x', 150)
.attr('y', 12)
.attr('text-anchor', 'end')
.text(item.value);
}
アニメーション効果の追加
show() と hide() に transition() を組み込むことで、フェードイン・フェードアウトのアニメーションを実現できます。
show() {
this.svg.transition()
.duration(300)
.style('opacity', 1)
.style('visibility', 'visible');
}
hide() {
this.svg.transition()
.duration(300)
.style('opacity', 0)
.on('end', () => {
this.svg.style('visibility', 'hidden');
});
}
実際の利用例
以下のコードは折れ線グラフにカスタムツールチップを導入した完全なサンプルです。テーマカラー、動的更新、マウスイベントとの連携をすべて含んでいます。
<html>
<head>
<title>カスタムツールチップの実装例</title>
<script src="https://cdn.jsdelivr.net/npm/chart.xkcd@1.1.11/dist/chart.xkcd.min.js"></script>
</head>
<body>
<div id="chart"></div>
<script>
const svg = document.querySelector("#chart");
const chart = new chartXkcd.Line(svg, {
title: "ユーザー増加トレンド",
xLabel: "月",
yLabel: "人数",
data: {
labels: ["1月", "2月", "3月"],
datasets: [{ label: "新規登録", data: [120, 190, 300] }]
}
});
const tooltip = new chartXkcd.Tooltip({
parent: chart.svg,
title: "詳細情報",
items: [{ color: "#e74c3c", text: "読み込み中..." }],
position: { type: "upRight", x: 0, y: 0 },
backgroundColor: "rgba(52, 152, 219, 0.9)",
strokeColor: "#ffffff"
});
chart.svg.selectAll(".dot")
.on("mouseover", function(event, d) {
tooltip.update({
title: `${chart.data.labels[d.index]}のデータ`,
items: [{
color: "#e74c3c",
label: "新規ユーザー数",
value: chart.data.datasets[0].data[d.index]
}],
position: { type: "upRight", x: event.pageX, y: event.pageY }
});
tooltip.show();
})
.on("mouseout", () => tooltip.hide())
.on("mousemove", (event) => {
tooltip.update({
position: { type: "upRight", x: event.pageX, y: event.pageY }
});
});
</script>
</body>
</html>
これらのアプローチを通じて、chart.xkcdのツールチップをビジネス要件に合わせてカスタマイズでき、より直感的かつ魅力的なデータ視覚化が実現します。詳細な設定については、公式ドキュメントの docs/04-line.md および docs/06-bar.md におけるインタラクションセクションをご参照ください。