integrate-file-viewer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Integrate CogniteFileViewer

集成CogniteFileViewer

Add
CogniteFileViewer
to this Dune app to preview CDF files (PDF, image, text).
CogniteFileViewer
添加到Dune应用中,以预览CDF文件(PDF、图片、文本)。

Your job

任务要求

Complete these steps in order. Read each file before modifying it.

按顺序完成以下步骤,修改文件前请先阅读相关内容。

Step 1 — Understand the app

步骤1 — 了解应用

Read these files before touching anything:
  • package.json
    — detect package manager (
    packageManager
    field or lock file) and existing deps
  • vite.config.ts
    — understand current Vite setup
  • The component where the viewer should be added

修改任何内容前,请先阅读以下文件:
  • package.json
    — 检测包管理器(
    packageManager
    字段或锁文件)及已存在的依赖
  • vite.config.ts
    — 了解当前Vite配置
  • 需要添加文件查看器的组件

Step 2 — Install dependencies

步骤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
ships as a dependency of
react-pdf
at the correct version — do not install it separately.

  • 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
的依赖已附带正确版本——请勿单独安装。

Step 3 — Configure the PDF.js worker

步骤3 — 配置PDF.js Worker

The consumer app must configure the PDF.js worker. This ensures the worker version matches the
pdfjs-dist
version shipped with your
react-pdf
install.
Add this setup in the same file where
CogniteFileViewer
is used (module execution order matters):
tsx
import { pdfjs } from 'react-pdf';

pdfjs.GlobalWorkerOptions.workerSrc = new URL(
  'pdfjs-dist/build/pdf.worker.min.mjs',
  import.meta.url,
).toString();
pnpm users: pnpm's strict linking may prevent the browser from resolving
pdfjs-dist
. Either add
pdfjs-dist
as a direct dependency (
pnpm add pdfjs-dist
), or add
public-hoist-pattern[]=pdfjs-dist
to
.npmrc
.

消费应用必须配置PDF.js Worker,确保Worker版本与
react-pdf
附带的
pdfjs-dist
版本匹配。
在使用
CogniteFileViewer
同一文件中添加以下配置(模块执行顺序很重要):
tsx
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

Step 4 — Configure Vite

步骤4 — 配置Vite

Add
optimizeDeps.exclude: ['pdfjs-dist']
to
vite.config.ts
to prevent Vite from pre-bundling pdfjs-dist (which breaks the worker):
ts
export default defineConfig({
  // ... existing config ...
  optimizeDeps: {
    exclude: ['pdfjs-dist'],
  },
});

vite.config.ts
中添加
optimizeDeps.exclude: ['pdfjs-dist']
,防止Vite预打包pdfjs-dist(这会导致Worker失效):
ts
export default defineConfig({
  // ... 现有配置 ...
  optimizeDeps: {
    exclude: ['pdfjs-dist'],
  },
});

Step 5 — Use the component

步骤5 — 使用组件

Import and render
CogniteFileViewer
wherever a file preview is needed.
tsx
import { CogniteFileViewer } from '@cognite/dune-industrial-components/file-viewer';
Get the
sdk
from the
useDune()
hook (already available in every Dune app):
tsx
import { useDune } from '@cognite/dune';
const { sdk } = useDune();
在需要文件预览的地方导入并渲染
CogniteFileViewer
tsx
import { CogniteFileViewer } from '@cognite/dune-industrial-components/file-viewer';
useDune()
钩子中获取
sdk
(每个Dune应用中都已内置该钩子):
tsx
import { useDune } from '@cognite/dune';
const { sdk } = useDune();

Supported file types

支持的文件类型

TypeFormats
PDF
.pdf
— page navigation, zoom, pan, diagram annotation overlay
Office documentsWord, PowerPoint, Excel, ODS, ODP, ODT, RTF, TSV — converted to PDF via the CDF Document Preview API, then rendered identically to PDF
ImageJPEG, PNG, WebP, SVG, TIFF — zoom, pan, rotation
Text
.txt
,
.csv
,
.json
— rendered as preformatted text
OtherFalls back to
renderUnsupported
类型格式
PDF
.pdf
— 支持页面导航、缩放、平移、图表批注叠加
办公文档Word、PowerPoint、Excel、ODS、ODP、ODT、RTF、TSV — 通过CDF文档预览API转换为PDF,然后以PDF格式渲染
图片JPEG、PNG、WebP、SVG、TIFF — 支持缩放、平移、旋转
文本
.txt
.csv
.json
— 以预格式化文本渲染
其他回退到
renderUnsupported
渲染

Minimal usage

最简使用示例

This is all you need — zoom, pan, and touch gestures are handled internally:
tsx
<CogniteFileViewer
  source={{ type: 'internalId', id: file.id }}
  client={sdk}
  style={{ width: '100%', height: '600px' }}
/>
The component needs a defined height. If the parent has no explicit height, the viewer will collapse to zero. Always set a
height
via
style
,
className
, or the parent container.
以下代码即可实现基础功能——缩放、平移及触摸手势均已内置:
tsx
<CogniteFileViewer
  source={{ type: 'internalId', id: file.id }}
  client={sdk}
  style={{ width: '100%', height: '600px' }}
/>
组件需要设置明确高度。如果父容器没有显式高度,查看器会收缩为零高度。请始终通过
style
className
或父容器设置
height

File source

文件源

Pass any of three source types:
tsx
// 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' }}
/>
Prefer
instanceId
when available
— it's the only source type that enables the diagram annotation overlay. When listing files via
sdk.files.list()
, check
file.instanceId
first:
tsx
source={
  file.instanceId
    ? { type: 'instanceId', space: file.instanceId.space, externalId: file.instanceId.externalId }
    : { type: 'internalId', id: file.id }
}
支持三种文件源类型:
tsx
// 通过实例ID(数据建模文件——支持批注)
<CogniteFileViewer
  source={{ type: 'instanceId', space: 'my-space', externalId: 'my-file' }}
  client={sdk}
/>

// 通过CDF内部ID
<CogniteFileViewer
  source={{ type: 'internalId', id: 12345 }}
  client={sdk}
/>

// 通过直接URL
<CogniteFileViewer
  source={{ type: 'url', url: 'https://...', mimeType: 'application/pdf' }}
/>
优先使用
instanceId
(如果可用)
——这是唯一支持图表批注叠加的文件源类型。通过
sdk.files.list()
列出文件时,请优先检查
file.instanceId
tsx
source={
  file.instanceId
    ? { type: 'instanceId', space: file.instanceId.space, externalId: file.instanceId.externalId }
    : { type: 'internalId', id: file.id }
}

Full props reference

完整属性参考

tsx
<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%' }}
/>

tsx
<CogniteFileViewer
  // 必填项
  source={source}
  client={sdk}              // 使用instanceId和internalId源时必填

  // PDF分页
  page={page}               // 受控当前页码(从1开始)
  onPageChange={setPage}
  onDocumentLoad={({ numPages }) => setNumPages(numPages)}

  // 缩放与平移(支持PDF和图片)
  zoom={zoom}               // 1 = 100%;内置Ctrl/Cmd+滚轮、捏合缩放、中键拖动功能
  onZoomChange={setZoom}
  minZoom={0.25}            // 默认值
  maxZoom={5}               // 默认值
  panOffset={pan}           // 受控平移偏移量;切换页面时会重置
  onPanChange={setPan}

  // 适配模式
  fitMode="width"           // 'width' 适配容器宽度;'page' 使整个页面适配容器

  // 旋转(支持PDF和图片)
  rotation={rotation}       // 0 | 90 | 180 | 270

  // 图表批注(仅instanceId源支持)
  showAnnotations={true}    // 默认值
  onAnnotationClick={(annotation) => { /* annotation.linkedResource包含space + externalId */ }}
  onAnnotationHover={(annotation) => {}}

  // 自定义批注提示框(替换原生<title>提示框)
  renderAnnotationTooltip={(annotation, rect) => (
    <div style={{
      position: 'absolute',
      left: rect.x + rect.width,
      top: rect.y,
      zIndex: 11,
    }}>
      {annotation.text}
    </div>
  )}

  // 自定义叠加层(SVG路径、高亮、绘图——支持PDF和图片)
  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>
  )}

  // 自定义渲染器(均为可选)
  renderLoading={() => <MySpinner />}
  renderError={(error) => <MyError message={error.message} />}
  renderUnsupported={(mimeType) => <div>无法预览 {mimeType}</div>}

  // 布局
  className="..."
  style={{ width: '100%', height: '100%' }}
/>

Tips & tricks

技巧与提示

Reset page, zoom and rotation when the source changes. The component does not reset these automatically when you switch files — do it yourself:
ts
const navigateToFile = (file: FileInfo) => {
  setSelectedFile(file);
  setPage(1);
  setZoom(1);
  setRotation(0);
};
Gate pagination UI on
numPages > 0
.
onDocumentLoad
only fires for PDFs. Don't render pagination controls until you know there are pages to paginate:
tsx
{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 click → navigate to linked file.
annotation.linkedResource
contains the
space
and
externalId
of the linked CDF instance. Match it against
file.instanceId
to navigate:
ts
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);
}}
Touch support is built in. Two-finger pinch-to-zoom and two-finger drag-to-pan work on touch devices automatically. No configuration needed.
Pan is middle-click drag (when zoomed in) on desktop. Left-click remains free for annotation clicks and text selection.
Ctrl/Cmd + wheel zooms toward the cursor — also built in. Wire
zoom
/
onZoomChange
if you want programmatic zoom buttons or to persist zoom state; otherwise it works fully uncontrolled.
renderOverlay
receives original page dimensions
(
originalWidth
,
originalHeight
) so you can set up an SVG
viewBox
in the original coordinate space. Paths drawn in PDF-point or image-pixel coordinates will map correctly to the rendered page at any zoom level.

切换文件源时重置页码、缩放和旋转。组件不会自动重置这些状态,请手动处理:
ts
const navigateToFile = (file: FileInfo) => {
  setSelectedFile(file);
  setPage(1);
  setZoom(1);
  setRotation(0);
};
仅当
numPages > 0
时渲染分页UI
onDocumentLoad
仅针对PDF触发。在确认有可分页的页面之前,请勿渲染分页控件:
tsx
{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
匹配以实现跳转:
ts
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点或图像像素坐标绘制的路径都会正确映射到渲染页面。

Common pitfalls

常见问题

ProblemCauseFix
Failed to resolve module specifier 'pdf.worker.mjs'
Worker not configuredAdd the worker setup from Step 3 in the same file that uses
CogniteFileViewer
API version does not match Worker version
pdfjs-dist
version mismatch between app and
react-pdf
Do not install
pdfjs-dist
separately — let
react-pdf
provide it. If already installed, remove it
Annotations never show
instanceId
is
undefined
— annotation overlay is disabled without it
Use
instanceId
source, or fall back and accept no annotations for classic files
Annotations show but are emptyFile has no
CogniteDiagramAnnotation
edges in CDF
Expected — only P&ID/diagram files synced to the data model have annotations
Viewer collapses to zero heightParent has no explicit heightSet
height
via
style
,
className
, or parent CSS
问题原因解决方法
Failed to resolve module specifier 'pdf.worker.mjs'
未配置Worker在使用
CogniteFileViewer
的同一文件中添加步骤3的Worker配置
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