integrate-file-viewer について
Dune アプリに CogniteFileViewer を追加し、CDF ファイルをプレビューするためのスキルです。依存関係や Vite、PDF.js worker の設定と、対応形式や操作方法を説明します。
主な機能
- 01ビューアー依存関係の導入
- 02PDF.js worker の設定
- 03Vite の pdfjs-dist 事前バンドル除外
- 04PDF、Office、画像、テキストのプレビュー
- 05ズーム、パン、注釈への対応
活用シーン
- 01Dune アプリへのファイルプレビュー追加
- 02CDF Document Preview API による Office 文書の表示
- 03注釈から関連ファイルへの移動
MCP 対応
ビューアーは Dune SDK を使って CDF ファイルにアクセスします。Office 文書は CDF Document Preview API で変換されます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ cognitedata/ dune-skills --skill integrate-file-viewerインストール後、Claude Code で/integrate-file-viewerを入力して読み込まれたか確認します。
詳細
CogniteFileViewer の統合
この Dune アプリに CogniteFileViewer を追加し、CDF ファイル(PDF、画像、テキスト)をプレビューできるようにします。
作業内容
以下の手順を順番に実施してください。変更を加える前に、各ファイルを読み込んでください。
手順 1 — アプリを理解する
作業に取りかかる前に、以下のファイルを読み込んでください。
package.json— パッケージマネージャー(packageManagerフィールドまたはロックファイル)と既存の依存関係を確認しますvite.config.ts— 現在の Vite 設定を確認します- ビューアーを追加するコンポーネント
手順 2 — 依存関係をインストールする
- pnpm →
pnpm add "github:cognitedata/dune-industrial-components#semver:*" react-pdf - npm →
npm install "github:cognitedata/dune-industrial-components#semver:*" react-pdf - yarn →
yarn add "github:cognitedata/dune-industrial-components#semver:*" react-pdf
pdfjs-dist は適切なバージョンが react-pdf の依存関係として含まれています。別途インストールしないでください。
手順 3 — PDF.js ワーカーを設定する
利用側のアプリで PDF.js ワーカーを設定する必要があります。これにより、ワーカーのバージョンが、インストールした react-pdf に含まれる pdfjs-dist のバージョンと一致します。
CogniteFileViewer を使用するファイルと同じファイルに、次の設定を追加してください(モジュールの実行順序が重要です)。
import { pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url,
).toString();
pnpm を使用する場合: pnpm の厳密なリンク設定により、ブラウザーから
pdfjs-distを解決できないことがあります。その場合は、pdfjs-distを直接の依存関係として追加する(pnpm add pdfjs-dist)か、.npmrcにpublic-hoist-pattern[]=pdfjs-distを追加してください。
手順 4 — Vite を設定する
Vite が pdfjs-dist を事前バンドルしないように(ワーカーが正常に動作しなくなるため)、vite.config.ts に optimizeDeps.exclude: ['pdfjs-dist'] を追加してください。
export default defineConfig({
// ... existing config ...
optimizeDeps: {
exclude: ['pdfjs-dist'],
},
});
手順 5 — コンポーネントを使用する
ファイルのプレビューが必要な箇所で、CogniteFileViewer をインポートしてレンダリングしてください。
import { CogniteFileViewer } from '@cognite/dune-industrial-components/file-viewer';
sdk は、すべての Dune アプリで使用できる useDune() フックから取得します。
import { useDune } from '@cognite/dune';
const { sdk } = useDune();
サポートされているファイル形式
| 種類 | 形式 |
|---|---|
.pdf — ページ移動、ズーム、パン、図面への注釈オーバーレイ | |
| Office ドキュメント | Word、PowerPoint、Excel、ODS、ODP、ODT、RTF、TSV — CDF Document Preview API を介して PDF に変換され、PDF と同様にレンダリングされます |
| 画像 | JPEG、PNG、WebP、SVG、TIFF — ズーム、パン、回転 |
| テキスト | .txt、.csv、.json — 書式を保持したテキストとしてレンダリングされます |
| その他 | renderUnsupported にフォールバックします |
最小限の使用例
必要な設定はこれだけです。ズーム、パン、タッチ操作は内部で処理されます。
<CogniteFileViewer
source={{ type: 'internalId', id: file.id }}
client={sdk}
style={{ width: '100%', height: '600px' }}
/>
コンポーネントには高さの設定が必要です。 親要素に明示的な高さがない場合、ビューアーの高さは 0 になります。必ず
style、className、または親コンテナーでheightを設定してください。
ファイルソース
以下の 3 種類のソースのいずれかを渡してください。
// By instance ID (data-modelled file — enables annotations)
<CogniteFileViewer
source={{ type: 'instanceId', space: 'my-space', externalId: 'my-file' }}
client={sdk}
/>
// By CDF internal ID
<CogniteFileViewer
source={{ type: 'internalId', id: 12345 }}
client={sdk}
/>
// By direct URL
<CogniteFileViewer
source={{ type: 'url', url: 'https://...', mimeType: 'application/pdf' }}
/>
可能であれば instanceId を使用してください。 図面への注釈オーバーレイを有効にできるのは、このソースタイプだけです。sdk.files.list() でファイルを一覧表示する際は、まず file.instanceId を確認してください。
source={
file.instanceId
? { type: 'instanceId', space: file.instanceId.space, externalId: file.instanceId.externalId }
: { type: 'internalId', id: file.id }
}
props の全項目
<CogniteFileViewer
// Required
source={source}
client={sdk} // required for instanceId and internalId sources
// PDF pagination
page={page} // controlled current page (1-indexed)
onPageChange={setPage}
onDocumentLoad={({ numPages }) => setNumPages(numPages)}
// Zoom & pan (works on PDF and images)
zoom={zoom} // 1 = 100%; Ctrl/Cmd+wheel, pinch-to-zoom, and middle-click drag built in
onZoomChange={setZoom}
minZoom={0.25} // default
maxZoom={5} // default
panOffset={pan} // controlled pan offset; resets on page change
onPanChange={setPan}
// Fit mode
fitMode="width" // 'width' fits to container width; 'page' fits entire page in container
// Rotation (PDFs and images)
rotation={rotation} // 0 | 90 | 180 | 270
// Diagram annotations (instanceId sources only)
showAnnotations={true} // default
onAnnotationClick={(annotation) => { /* annotation.linkedResource has space + externalId */ }}
onAnnotationHover={(annotation) => {}}
// Custom annotation tooltip (replaces native <title> tooltip)
renderAnnotationTooltip={(annotation, rect) => (
<div style={{
position: 'absolute',
left: rect.x + rect.width,
top: rect.y,
zIndex: 11,
}}>
{annotation.text}
</div>
)}
// Custom overlay (SVG paths, highlights, drawings — works on PDF and images)
renderOverlay={({ width, height, originalWidth, originalHeight, pageNumber, rotation }) => (
<svg
width={width}
height={height}
viewBox={`0 0 ${originalWidth} ${originalHeight}`}
preserveAspectRatio="none"
style={{ position: 'absolute', top: 0, left: 0, pointerEvents: 'all' }}
>
<path d="..." stroke="cyan" fill="none" />
</svg>
)}
// Custom renderers (all optional)
renderLoading={() => <MySpinner />}
renderError={(error) => <MyError message={error.message} />}
renderUnsupported={(mimeType) => <div>Cannot preview {mimeType}</div>}
// Layout
className="..."
style={{ width: '100%', height: '100%' }}
/>
ヒントとコツ
ソースが変わったら、ページ、ズーム、回転をリセットします。 ファイルを切り替えても、コンポーネントはこれらを自動的にリセットしません。手動で行ってください。
const navigateToFile = (file: FileInfo) => {
setSelectedFile(file);
setPage(1);
setZoom(1);
setRotation(0);
};
numPages > 0 の場合にページネーション UI を表示します。
onDocumentLoad は PDF の場合にのみ実行されます。ページ数がわかるまでは、ページネーションコントロールを表示しないでください。
{numPages > 0 && (
<>
<button disabled={page <= 1} onClick={() => setPage(p => p - 1)}>‹</button>
<span>{page} / {numPages}</span>
<button disabled={page >= numPages} onClick={() => setPage(p => p + 1)}>›</button>
</>
)}
アノテーションのクリックから、リンク先のファイルに移動します。
annotation.linkedResource には、リンク先の CDF インスタンスの space と externalId が含まれています。これらを file.instanceId と照合して移動します。
onAnnotationClick={(annotation) => {
if (!annotation.linkedResource) return;
const { space, externalId } = annotation.linkedResource;
const linked = files.find(
f => f.instanceId?.space === space && f.instanceId?.externalId === externalId
);
if (linked) navigateToFile(linked);
}}
タッチ操作に標準対応しています。 タッチデバイスでは、2 本指でのピンチによるズームと、2 本指でのドラッグによるパンが自動的に機能します。設定は不要です。
デスクトップでは、パンは中クリックでドラッグして行います(ズームイン時)。左クリックはアノテーションのクリックやテキストの選択に使用できます。
Ctrl/Cmd + ホイールでカーソル位置に向かってズームします。こちらも標準機能です。プログラムによるズームボタンを追加したり、ズーム状態を保持したりする場合は、zoom/onZoomChange を接続してください。それ以外の場合は、完全に非制御で動作します。
renderOverlay には元のページ寸法(originalWidth、originalHeight)が渡されるため、元の座標空間で SVG の viewBox を設定できます。PDF ポイントまたは画像ピクセル単位で描画したパスは、ズームレベルにかかわらず、レンダリングされたページに正しく対応します。
よくある問題
| 問題 | 原因 | 解決方法 |
|---|---|---|
Failed to resolve module specifier 'pdf.worker.mjs' | ワーカーが設定されていません | CogniteFileViewer を使用するファイルに、手順 3 のワーカー設定を追加します |
API version does not match Worker version | アプリと react-pdf の間で pdfjs-dist のバージョンが一致していません | pdfjs-dist を個別にインストールせず、react-pdf が提供するものを使用します。すでにインストール済みの場合は削除してください |
| アノテーションがまったく表示されません | instanceId が undefined です。指定されていない場合、アノテーションオーバーレイは無効になります | instanceId のソースを使用するか、従来形式のファイルではアノテーションが表示されないことを許容して代替方法を使用します |
| アノテーションは表示されますが、中身が空です | ファイルに CDF の CogniteDiagramAnnotation エッジがありません | 想定される動作です。アノテーションがあるのは、データモデルに同期された P&ID/図面ファイルのみです |
| ビューアーの高さがゼロになります | 親要素に明示的な高さがありません | style、className、または親要素の CSS で height を設定します |