npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@njboea/js-3d-model

v0.3.0

Published

Cornerstone3D DICOM viewer library - Simplified API for medical image viewing

Readme

@njboea/js-3d-model

Cornerstone3D DICOM 查看器库 - 简化的医学影像查看 API

Version License

🌟 特性

  • 🚀 简化的 API:封装 Cornerstone3D 复杂性,提供简洁易用的接口
  • 📦 开箱即用:自动初始化,无需复杂配置
  • 🎯 多种加载方式:支持本地文件、WADO-RS、ZIP 文件
  • 🛠️ 丰富的工具:内置窗宽窗位、测量、标注等工具
  • 💾 标注管理:完整的标注增删改查和导出功能
  • 🎨 框架无关:可在 Vue、React、Angular 或原生 JS 中使用

📦 安装

npm install @njboea/js-3d-model
# 或
yarn add @njboea/js-3d-model

Peer 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 - 矩形 ROI
  • Angle - 角度测量
  • EllipticalROI - 椭圆 ROI
  • Probe - 探针

注意:

  • 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