integrate-file-viewer について
Cognite Flows アプリに CogniteFileViewer を組み込み、CDF ファイルをプレビューするためのスキルです。コンポーネントの配置、依存関係と Vite の設定に加え、対応形式や注釈、操作方法を説明します。
主な機能
- 01PDF、Office 文書、画像、テキストのプレビュー
- 02PDF のページ移動とズーム
- 03画像のズーム、パン、回転
- 04関連する図面注釈の表示
- 05タッチ操作とカーソル位置へのズーム
活用シーン
- 01Flows アプリに CDF ファイルのプレビューを追加
- 02PDF の図面注釈を確認し、リンク先ファイルを開く
- 03タッチデバイスで文書をパン、ズーム
- 04テキスト、画像、Office ファイルを表示
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ cognitedata/ builder-skills --skill integrate-file-viewerインストール後、Claude Code で/integrate-file-viewerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
code/CogniteFileViewer.tsxDocumentAnnotationOverlay.tsxfileResolution.tsindex.tsmimeTypes.tstypes.tsuseDocumentAnnotations.tsuseFileResolver.tsuseViewport.ts詳細
CogniteFileViewer を統合する
この Flows アプリに CogniteFileViewer を追加し、CDF ファイル(PDF、画像、テキスト)をプレビューできるようにします。
依存関係
ファイルビューアーのライブラリファイル(ステップ 2 でコピー)は、次の npm パッケージを必要とします。
| パッケージ | バージョン |
|---|---|
react-pdf | ^9.1.1 |
pdfjs-dist は適切なバージョンの react-pdf の依存関係として含まれています。別途インストールしないでください。
react と @cognite/sdk は、Flows アプリにすでに含まれていることを前提としています。
作業内容
以下の手順を順番に完了してください。変更する前に各ファイルを読んでください。
ステップ 1 — アプリを理解する
作業を始める前に、次のファイルを読んでください。
package.json— パッケージマネージャー(packageManagerフィールドまたはロックファイル)と既存の依存関係を確認しますvite.config.ts— 現在の Vite 設定を確認します- ビューアーを追加するコンポーネント
ステップ 2 — ファイルビューアーのソースファイルをコピーする
ファイルビューアーのライブラリは、このスキルファイルと同じ階層の code/ ディレクトリにあります。そこにあるすべてのファイルを読み、アプリ内の src/cognite-file-viewer/ にコピーしてください。
code/types.tscode/mimeTypes.tscode/fileResolution.tscode/useViewport.tscode/useFileResolver.tscode/useDocumentAnnotations.tscode/DocumentAnnotationOverlay.tsxcode/CogniteFileViewer.tsxcode/index.ts
PDF.js ワーカーは
CogniteFileViewer.tsx内で設定されるため、利用側で別途設定する必要はありません。
ステップ 3 — 依存関係をインストールする
アプリのパッケージマネージャーを使って、上記の依存関係に記載されている react-pdf をインストールしてください。
- pnpm →
pnpm add react-pdf@^9.1.1 - npm →
npm install react-pdf@^9.1.1 - yarn →
yarn add react-pdf@^9.1.1
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-file-viewer';
useDune() フックから sdk を取得してください(すべての Flows アプリで利用できます)。
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);
};
ページネーション UI は numPages > 0 の場合にのみ表示します。
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' | pdfjs-dist が hoist されていない(pnpm) | .npmrc に public-hoist-pattern[]=pdfjs-dist を追加するか、pnpm add pdfjs-dist を直接実行します |
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 を設定します |