mcpField
I
integrate-file-viewer

integrate-file-viewer

github.com/cognitedata文档处理61.9k 次安装1 天前更新
代码仓库

关于 integrate-file-viewer

用于在 Cognite Flows 应用中集成 CogniteFileViewer 的技能,可预览 CDF 文件。涵盖组件复制、依赖和 Vite 配置,以及文件类型、注释和交互操作的使用说明。

主要功能

  1. 01预览 PDF、办公文档、图像和文本
  2. 02提供 PDF 页面导航与缩放
  3. 03支持图像缩放、平移和旋转
  4. 04显示关联图表注释
  5. 05支持触控手势和光标缩放

适用场景

  1. 01在 Flows 应用中添加 CDF 文件预览
  2. 02查看 PDF 中的图表注释并跳转关联文件
  3. 03在触屏设备上平移和缩放文档
  4. 04渲染文本、图像及办公文件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cognitedata/builder-skills --skill integrate-file-viewer

安装后在 Claude Code 中输入/integrate-file-viewer确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

code/
CogniteFileViewer.tsx
DocumentAnnotationOverlay.tsx
fileResolution.ts
index.ts
mimeTypes.ts
types.ts
useDocumentAnnotations.ts
useFileResolver.ts
useViewport.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.ts
  • code/mimeTypes.ts
  • code/fileResolution.ts
  • code/useViewport.ts
  • code/useFileResolver.ts
  • code/useDocumentAnnotations.ts
  • code/DocumentAnnotationOverlay.tsx
  • code/CogniteFileViewer.tsx
  • code/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.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

评论

支持 Markdown