@njboea/js-3d-model
v0.3.0
Published
Cornerstone3D DICOM viewer library - Simplified API for medical image viewing
Maintainers
Readme
@njboea/js-3d-model
Cornerstone3D DICOM 查看器库 - 简化的医学影像查看 API
🌟 特性
- 🚀 简化的 API:封装 Cornerstone3D 复杂性,提供简洁易用的接口
- 📦 开箱即用:自动初始化,无需复杂配置
- 🎯 多种加载方式:支持本地文件、WADO-RS、ZIP 文件
- 🛠️ 丰富的工具:内置窗宽窗位、测量、标注等工具
- 💾 标注管理:完整的标注增删改查和导出功能
- 🎨 框架无关:可在 Vue、React、Angular 或原生 JS 中使用
📦 安装
npm install @njboea/js-3d-model
# 或
yarn add @njboea/js-3d-modelPeer Dependencies
需要同时安装以下依赖:
npm install @cornerstonejs/core @cornerstonejs/tools @cornerstonejs/dicom-image-loader jszip🚀 快速开始
1. 基础使用
import { Js3DModel } from '@njboea/js-3d-model';
// 创建实例
const js3d = new Js3DModel({
rendering: {
useCPURendering: false // 使用 GPU 渲染
},
imageLoader: {
maxWebWorkers: 2,
maxCacheSize: 512 * 1024 * 1024 // 512MB
}
});
// 初始化
await js3d.initialize();
// 创建视口
const viewportId = js3d.createViewport({
viewportId: 'main',
type: 'STACK',
element: document.getElementById('viewport')
});
// 加载 DICOM 文件
await js3d.loadLocalFiles(viewportId, files);
// 激活工具
js3d.activateTool(viewportId, 'Length');
// 获取标注
const annotations = js3d.getAllAnnotations();
// 清理资源
await js3d.destroy();2. 在 Vue3 中使用
<template>
<div>
<div v-if="isInitialized">
<!-- 工具栏 -->
<div class="toolbar">
<button @click="activateTool('WindowLevel')">窗宽窗位</button>
<button @click="activateTool('Pan')">平移</button>
<button @click="activateTool('Zoom')">缩放</button>
<button @click="activateTool('Length')">长度测量</button>
</div>
<!-- 视口 -->
<div
ref="viewportElement"
style="width: 512px; height: 512px; background: black;"
></div>
<!-- 文件上传 -->
<input type="file" multiple @change="handleFiles" accept=".dcm" />
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { Js3DModel } from '@njboea/js-3d-model';
const viewportElement = ref(null);
const isInitialized = ref(false);
const js3d = ref(null);
let viewportId = '';
onMounted(async () => {
// 创建并初始化
js3d.value = new Js3DModel({
imageLoader: { maxWebWorkers: 2, maxCacheSize: 512 * 1024 * 1024 }
});
await js3d.value.initialize();
isInitialized.value = true;
// 等待 DOM 元素挂载后创建视口
watch(viewportElement, (el) => {
if (el) {
viewportId = js3d.value.createViewport({
viewportId: 'main',
type: 'STACK',
element: el
});
}
}, { immediate: true });
});
onUnmounted(async () => {
if (js3d.value) {
await js3d.value.destroy();
}
});
async function handleFiles(event) {
const files = Array.from(event.target.files);
await js3d.value.loadLocalFiles(viewportId, files);
}
function activateTool(toolName) {
js3d.value.activateTool(viewportId, toolName);
}
</script>📖 API 文档
构造函数
const js3d = new Js3DModel(config);配置选项:
{
rendering: {
useCPURendering: false, // 是否使用 CPU 渲染
renderingEngineMode: 'contextPool',
webGlContextCount: 7
},
imageLoader: {
maxWebWorkers: 2, // Web Worker 数量
maxCacheSize: 512 * 1024 * 1024, // 缓存大小(字节)
decodeConfig: {
use16BitDataType: true
}
}
}核心方法
initialize()
初始化 Cornerstone3D。
await js3d.initialize();createViewport(config)
创建视口。
const viewportId = js3d.createViewport({
viewportId: 'main',
type: 'STACK', // 'STACK' | 'ORTHOGRAPHIC' | 'VOLUME_3D'
element: document.getElementById('viewport'),
defaultOptions: {
background: [0, 0, 0]
}
});loadLocalFiles(viewportId, files, options)
加载本地 DICOM 文件。
await js3d.loadLocalFiles(viewportId, files, {
autoSort: true,
onProgress: (progress) => {
console.log(progress.message, progress.percent);
}
});loadWadoRs(viewportId, studyUID, seriesUID, config, onProgress)
加载 WADO-RS 系列。
await js3d.loadWadoRs(
viewportId,
'studyUID',
'seriesUID',
{
wadoRsRoot: 'http://server/dicomweb',
headers: { 'Authorization': 'Bearer token' }
},
(progress) => console.log(progress.message)
);loadZipFile(viewportId, zipFile, onProgress)
加载 ZIP 文件。
await js3d.loadZipFile(viewportId, zipFile, (progress) => {
console.log(progress.stage, progress.percent);
});工具方法
activateTool(viewportId, toolName)
激活工具。
js3d.activateTool(viewportId, 'Length');可用工具:
WindowLevel- 窗宽窗位Pan- 平移Zoom- 缩放StackScroll- 翻页(滚轮,默认激活)Crosshairs- 十字线(⚠️ 需要多视口才能使用)Length- 长度测量RectangleROI- 矩形 ROIAngle- 角度测量EllipticalROI- 椭圆 ROIProbe- 探针
注意:
Crosshairs(十字线)工具需要至少两个视口才能正常工作,适用于 MPR 多视图场景- 在单视口场景下请不要使用十字线工具,否则会导致错误
getAvailableTools()
获取可用工具列表。
const tools = js3d.getAvailableTools();标注方法
getAllAnnotations(toolName)
获取所有标注。
const annotations = js3d.getAllAnnotations();
// 或获取特定工具的标注
const lengthAnnotations = js3d.getAllAnnotations('Length');removeAnnotation(annotationUID)
删除标注。
js3d.removeAnnotation(annotationUID);clearAllAnnotations()
清除所有标注。
js3d.clearAllAnnotations();exportAnnotations(toolName)
导出标注为 JSON。
const json = js3d.exportAnnotations();getAnnotationStats()
获取标注统计。
const stats = js3d.getAnnotationStats();
// { total: 5, byTool: { Length: 3, Angle: 2 }, byViewport: { ... } }其他方法
getViewport(viewportId)
获取视口对象。
const viewport = js3d.getViewport(viewportId);resetCamera(viewportId)
重置相机。
js3d.resetCamera(viewportId);getCacheInfo()
获取缓存信息。
const info = js3d.getCacheInfo();
// { size: 12345678, maxSize: 536870912, sizeFormatted: '11.77 MB', ... }clearCache()
清理缓存。
js3d.clearCache();destroy()
销毁所有资源。
await js3d.destroy();🔧 高级用法
单独使用管理器
import {
CornerstoneFacade,
ViewportManager,
ToolManager,
AnnotationManager
} from '@njboea/js-3d-model';
// 自定义初始化
const facade = new CornerstoneFacade(config);
await facade.initialize();
// 使用各个管理器
const viewportManager = new ViewportManager();
const toolManager = new ToolManager();使用工具函数
import { sortImageIdsByPosition, isDicomFile } from '@njboea/js-3d-model';
// 排序图像
const sortedIds = await sortImageIdsByPosition(imageIds);
// 检查文件
if (isDicomFile(file)) {
// 处理 DICOM 文件
}📝 示例
查看 examples/ 目录获取更多示例:
🤝 贡献
欢迎贡献代码!请阅读 CONTRIBUTING.md 了解详情。
📄 许可
MIT License - 详见 LICENSE
🔗 相关链接
🙏 致谢
本项目基于 Cornerstone3D 构建。
版本: v0.2.0
更新日期: 2025-11-16
