PDF をブラウザ上で表示する際に、マウスカーソル(ポインター)の見た目を変えることで、ユーザー体験を向上させることができます。本記事では、PDF.js を利用した基本的なサンプルをもとに、初心者でも 3 分で実装できる「ポインター表示を簡単にカスタマイズする方法」を紹介します。開発環境や実装手順を簡潔にまとめ、必要ならコードをそのままコピーしてすぐに動かせるようにしています。
はじめに:ポインターカスタマイズのメリット
-
視覚的なアクセント
PDF 内のリンクやテキスト選択時にカーソルを変えることで、インタラクティブな感覚を演出できます。 -
アクセシビリティの向上
色弱や視覚障害のあるユーザーにも利用しやすいピンポイントなデザインを提供。 -
ブランドイメージの一貫性
カスタムポインターを企業のロゴやアイコンに合わせることで、統一感を持たせることができます。
1. 必要な環境とセットアップ
① Node.js と npm のインストール
PDF.js をローカルで実行するために、Node.js(v18以上推奨)が必要です。
公式サイト(Node.js Download)からインストールしてください。
② プロジェクトディレクトリを作成
mkdir pdf-pointer-demo
cd pdf-pointer-demo
③ PDF.js を導入
npm init -y
npm install pdfjs-dist
④ シンプルなサーバーを立てる(任意)
ローカルで閲覧するだけなら、http-server などを使用すると便利です。
npm install --save-dev http-server
npx http-server
(http://localhost:8080 でアクセス出来ます)
2. ベースとなる HTML・CSS
以下を index.html として作成します。ここでは PDF ビューア用の <canvas> といくつかのスタイルを設定しています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PDF Pointer Demo</title>
<style>
body {
margin: 0;
font-family: sans-serif;
background: #f4f4f4;
}
#pdf-container {
position: relative;
overflow: auto;
height: 100vh;
background: #fff;
}
/* カスタムポインターを定義したい状態のクラス */
.pdf-cursor-pointer {
cursor: url('pointer-cursor.png'), auto;
}
.pdf-cursor-text {
cursor: url('text-cursor.png'), text;
}
.pdf-cursor-default {
cursor: default;
}
</style>
</head>
<body>
<div id="pdf-container"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.14.169/pdf.min.js"></script>
<script src="app.js"></script>
</body>
</html>
ポイント
cursor: url('pointer-cursor.png'), auto;で、任意の画像をカーソルに設定できます。- 画像は
./pointer-cursor.pngなど、実際に配置しているパスを指定してください。- もし画像がなく、単純な形状で十分なら、CSS の
cursorにpointer、text、crosshair等のキーワードだけで設定できます。
3. PDF.js で PDF を描画する基本コード
次に、app.js を作成し、簡単に PDF を表示します。
const pdfUrl = 'sample.pdf'; // 表示したい PDF ファイルのパス
const container = document.getElementById('pdf-container');
// PDF.js のワーカーを設定
pdfjsLib.GlobalWorkerOptions.workerSrc = '//cdnjs.cloudflare.com/ajax/libs/pdf.js/4.14.169/pdf.worker.min.js';
// PDF をロード
pdfjsLib.getDocument(pdfUrl).promise.then(pdf => {
// 1ページだけ描画(サンプル)
pdf.getPage(1).then(page => {
const viewport = page.getViewport({ scale: 1.5 });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = viewport.width;
canvas.height = viewport.height;
container.appendChild(canvas);
const renderContext = {
canvasContext: context,
viewport
};
page.render(renderContext);
});
});
注意
- このコードは「1ページだけ」を描画する最小構成です。
sample.pdfは同じフォルダに配置しておくか、インターネット上にある URL を指してください。
4. マウスイベントでカーソルを動的に変更
① クリック時にリンクカーソルへ
PDF のリンク(<a> タグ)は、page.getAnnotations() で取得できます。リンクにマウスオーバーしたらカーソルを pointer に変更する簡単サンプルです。
// PDF の注釈を取得
pdf.getAnnotations({ intent: 'display' }).then(annotations => {
annotations.forEach(ann => {
if (ann.subtype === 'Link') {
// クリック領域を作成
const linkRect = page.getViewport({ scale: 1.5 }).convertToViewportRectangle(ann.rect);
const [x1, y1, x2, y2] = linkRect;
const linkEl = document.createElement('div');
linkEl.style.position = 'absolute';
linkEl.style.left = `${x1}px`;
linkEl.style.top = `${y1}px`;
linkEl.style.width = `${x2 - x1}px`;
linkEl.style.height = `${y2 - y1}px`;
linkEl.style.cursor = 'pointer';
// クリック時にリンク先へ遷移
linkEl.addEventListener('click', () => {
window.open(ann.url, '_blank');
});
container.appendChild(linkEl);
}
});
});
ポイント
linkElは実際の PDF 画面上に重ねられる「透明な DIV」です。- この DIV の
cursorをpointerに設定するだけで、リンク上にカーソルが変わります。
② テキスト選択時にテキストカーソルへ
デフォルトではテキスト選択時に text カーソルが自動で付与されますが、もし別のカーソル画像を使いたい場合は、選択状態を検知して CSS を付与します。
container.addEventListener('mousedown', () => {
container.classList.add('pdf-cursor-text');
});
container.addEventListener('mouseup', () => {
container.classList.remove('pdf-cursor-text');
});
備考
- ここではマウスダウンで「テキスト選択中」とみなし、クラスを追加。
- 実際は
window.getSelection().rangeCountをチェックして選択があるかどうか確認できます。
③ デフォルトのカーソルへ戻す
ページ上にマウスを移動し、リンクもテキスト選択も行っていない状態ではデフォルトに戻します。
container.addEventListener('mousemove', (e) => {
const target = e.target;
if (target.tagName === 'A' || target.tagName === 'DIV') {
return; // LINK / 選択領域はそのまま
}
container.classList.remove('pdf-cursor-text');
container.classList.remove('pdf-cursor-pointer');
container.classList.add('pdf-cursor-default');
});
5. カスタムカーソル画像を使うときの注意点
-
サイズ
- カーソル画像は 32×32 ピクセル程度が標準。
- それより大きいとシステムデフォルトより前面に表示され、操作がしにくくなる。
-
形式
.png(透明度付き)または.gifが推奨。- SVG も OK ですが、ブラウザ側でサポート状況が異なるため、PNG で統一することが安全です。
-
パス
cursor: url('/images/cursor.png'), auto;のように絶対パスで指定すると、CDN 等でも動くので外部ホスティングに向けて準備できます。
6. まとめ
| タスク | 実装の大まかな方法 | コードのハイライト |
|---|---|---|
| 1. PDF を表示 | PDF.js で canvas にレンダリング |
pdfjsLib.getDocument() → page.render() |
| 2. リンク領域を検知 | getAnnotations() でリンク情報取得 |
linkRect → div を重ねる |
| 3. カーソルを変更 | div の CSS cursor を設定 |
linkEl.style.cursor = 'pointer'; |
| 4. 一時的にカーソル変化 | イベントリスナーでクラス変更 | container.classList.add('pdf-cursor-text'); |
| 5. 画像を使う | PNG を用意し URL で指定 | cursor: url('pointer-cursor.png'), auto; |
実装速さ
このサンプルコードをベースにすれば、初心者でも 3 分程度で「PDF 上のリンクやテキスト選択時にカスタムポインター」を実装できます。
ただし、実際に動作させるには必ず PDF ファイルとカーソル画像を用意し、ローカルサーバーを立てる手順を踏む必要があります。
7. よくある質問
Q1. 画像を使わずに CSS だけでカーソルを変えたい場合は?
cursor: pointer; だけで十分です。CSS で cursor: crosshair; などを指定するだけで、ブラウザに描画されたカーソルに変更できます。
Q2. PDF の複数ページを表示したい場合は?
pdf.getPage(n) をループさせて、各ページごとに canvas を追加して表示します。リンク領域も各ページごとに取得する必要があります。
Q3. PDF.js のバージョンが古いとカスタムカーソルが効かない?
PDF.js のバージョンに関わらず、cursor の設定は CSS/DOM の操作なので、バージョンは関係ありません。しかし、古いバージョンでは getAnnotations() が正しく動作しないことがあるので、最新版(4.x 系)を使用することを推奨します。
8. さらに進めるには
-
アクセシビリティ
- カーソル画像の代わりに、
aria-hidden="true"で隠しつつ、スクリーンリーダーには別のインジケーターを設置。
- カーソル画像の代わりに、
-
レスポンシブ
- ビューポートに合わせてカスタムカーソルの位置やサイズを動的に調整。
-
イベントベースの拡張
- PDF 内の注釈(フォームフィールドやハイライト)を検知し、カーソルを変えることでインタラクティブな UI を構築。
最後に
この記事では、PDF.js を使った「簡単なカーソルカスタマイズ」を紹介しました。実際のプロジェクトに組み込む際は、ビューワー全体のデザインやユーザーの期待を考え、カーソル画像やクラス名を調整してください。
ぜひ試してみて、自分だけのオリジナル PDF ビューアを完成させてください!


コメント