关于 integrate-file-viewer
用于在 Cognite Flows 应用中集成 CogniteFileViewer 的技能,可预览 CDF 文件。涵盖组件复制、依赖和 Vite 配置,以及文件类型、注释和交互操作的使用说明。
主要功能
- 01预览 PDF、办公文档、图像和文本
- 02提供 PDF 页面导航与缩放
- 03支持图像缩放、平移和旋转
- 04显示关联图表注释
- 05支持触控手势和光标缩放
适用场景
- 01在 Flows 应用中添加 CDF 文件预览
- 02查看 PDF 中的图表注释并跳转关联文件
- 03在触屏设备上平移和缩放文档
- 04渲染文本、图像及办公文件
安装
复制下面的命令,在终端中运行。
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
将 CogniteFileViewer 添加到此 Flows 应用中,以预览 CDF 文件(PDF、图像、文本)。
依赖项
文件查看器库文件(在第 2 步中复制)需要以下 npm 包:
| 包 | 版本 |
|---|---|
react-pdf | ^9.1.1 |
pdfjs-dist 会以正确的版本作为 react-pdf 的依赖项一同安装;请勿单独安装。
假定 Flows 应用中已包含 react 和 @cognite/sdk。
你的任务
按顺序完成以下步骤。修改前先阅读每个文件。
第 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 worker 已在
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),或将public-hoist-pattern[]=pdfjs-dist添加到.npmrc。
第 4 步 — 配置 Vite
在 vite.config.ts 中添加 optimizeDeps.exclude: ['pdfjs-dist'],以防止 Vite 预打包 pdfjs-dist(这会导致 worker 无法正常工作):
export default defineConfig({
// ... existing config ...
optimizeDeps: {
exclude: ['pdfjs-dist'],
},
});
第 5 步 — 使用组件
从本地复制的文件中导入并渲染 CogniteFileViewer:
import { CogniteFileViewer } from './cognite-file-viewer';
通过 useDune() hook 获取 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' }}
/>
组件必须有明确的高度。 如果父容器没有显式高度,查看器会收缩至零。请始终通过
style、className或父容器设置height。
文件来源
传入以下三种来源类型之一:
// 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 }
}
完整属性参考
<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 时显示分页界面。
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);
}}
内置触控支持。 在触控设备上,双指捏合缩放和双指拖动平移会自动生效。无需配置。
在桌面端,缩放后可通过按住鼠标中键拖动来平移。 鼠标左键仍可用于点击注释和选择文本。
按住 Ctrl/Cmd 并滚动滚轮可朝光标位置缩放,此功能也已内置。如果想添加程序化缩放按钮或保存缩放状态,可接入 zoom/onZoomChange;否则,无需控制即可正常使用。
renderOverlay 接收原始页面尺寸(originalWidth、originalHeight),因此可以在原始坐标空间中设置 SVG viewBox。以 PDF 点或图像像素为单位绘制的路径,在任何缩放级别下都能正确映射到渲染后的页面。
常见问题
| 问题 | 原因 | 解决方法 |
|---|---|---|
Failed to resolve module specifier 'pdf.worker.mjs' | 未提升 pdfjs-dist(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 |