med-viewer-sdk 0.1.21 → 0.1.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,429 +1,707 @@
1
1
  # MedViewer SDK
2
2
 
3
- MedViewer SDK 是一个强大且灵活的医学图像查看 SDK,它基于 OpenSeadragon 构建,旨在为医学图像分析和注释提供丰富的交互功能。
4
-
5
- ## 功能特性
6
-
7
- - **高性能图像查看:** 利用 OpenSeadragon 实现高分辨率医学图像的无缝查看,支持深度缩放和平移功能。
8
- - **可定制工具栏:**
9
- - 动态且可配置的工具栏,可集成各种工具和插件。
10
- - 支持文本和图标按钮。
11
- - 按钮可以触发设置下拉菜单或直接执行操作。
12
- - 用户定义的按钮配置可以覆盖默认设置(图标、标签、功能)。
13
- - 响应式布局,侧边工具栏(MIDDLE_LEFT, MIDDLE_RIGHT)支持垂直方向。
14
- - **选择插件:**
15
- - 提供交互式选择功能(例如,绘制矩形)。
16
- - 可配置的选择外观和行为。
17
- - 与工具栏集成,方便访问和控制。
18
- - **比例尺插件:**
19
- - 在查看器上显示动态比例尺。
20
- - 支持不同类型的比例尺(例如,显微镜、地图)。
21
- - 可配置位置、颜色、字体和大小。
22
- - 自动初始化并与查看器的缩放级别同步。
23
- - **标注工具:**
24
- - **Annotorious 集成 (AnnoAnnotator):**
25
- - 集成 Annotorious 库以提供高级标注功能。
26
- - 支持各种标注工具(例如,徒手绘制、多边形)。
27
- - 提供启用/禁用、设置工具、获取/设置标注和清除标注的方法。
28
- - 动态注入自定义标注样式。
29
- - **Konva.js 集成 (KonvaAnnotator):**
30
- - 利用 Konva.js 实现自定义绘图覆盖。
31
- - 当前支持绘制矩形和可能的箭头(注释掉的同步逻辑表明可能计划了更复杂的交互)。
32
- - 允许拖动形状。
33
- - 无论缩放级别如何,都保持恒定的描边宽度 (`strokeScaleEnabled: false`)。
34
- - 提供启用/禁用、设置工具、获取/设置标注和清除标注的方法。
35
- - **颜色调整插件:**
36
- - 启用对图像属性(如亮度、对比度、饱和度、伽马、锐化、边缘增强、伪彩色和反色)的实时调整。
37
- - **利用 WebGL 着色器:** 直接在 GPU 上实现调整以提高性能。
38
- - 尝试强制 OpenSeadragon 使用其 WebGL 渲染器以获得最佳功能。
39
- - 提供自定义 WebGL 着色器用于高级颜色操作。
40
- - **基于插件的架构:**
41
- - SDK 采用模块化、基于插件的架构设计,以 `MedViewerEngine` 作为核心协调器。
42
- - 易于扩展以添加新功能。
43
- - 管理各种插件的生命周期(初始化、销毁)。
3
+ > 面向医学图像分析的高性能查看与标注 SDK,基于 OpenSeadragon 深度缩放引擎,提供插件化架构。
4
+
5
+ ## 特性
6
+
7
+ - **深度缩放** 基于 OpenSeadragon 的高性能瓦片渲染,支持超大病理切片无缝浏览
8
+ - **插件化架构** — 标注、截图、颜色调整、比例尺、放大镜、工具栏等插件按需启用
9
+ - **标注能力** — 集成 Annotorious,支持矩形/多边形/圆形/椭圆/线段/手绘 六种标注工具
10
+ - **颜色调整** — WebGL 加速的亮度/对比度/饱和度/伽马/色相/反色/灰度/怀旧 实时调节
11
+ - **区域截图** — 框选区域并导出为 Blob,支持旋转和像素坐标
12
+ - **工具栏** — 内置深色风格工具栏,支持自定义按钮、下拉面板、激活态
13
+ - **Vue 集成** — 提供 Vue 2/3 通用组件 `MedViewer`,自动管理生命周期
14
+ - **国际化** — 内置中文/英文,支持动态切换
15
+
16
+ ---
44
17
 
45
18
  ## 安装
46
19
 
47
20
  ```bash
48
- # 假设使用 npm yarn 进行包管理
49
- npm install openseadragon # 根据需要添加其他依赖
21
+ npm install med-viewer-sdk
50
22
  # 或
51
- yarn add openseadragon
23
+ pnpm add med-viewer-sdk
52
24
  ```
53
25
 
54
- 然后,在您的项目中引入 SDK:
26
+ **Peer Dependencies**(需自行安装):
55
27
 
56
- ```typescript
57
- import { MedViewerEngine } from 'med-viewer-sdk' // 根据需要调整路径
58
- // 如果有任何 CSS,请导入
28
+ ```bash
29
+ npm install openseadragon vue
59
30
  ```
60
31
 
61
- ## 用法
32
+ ---
62
33
 
63
- ### 基本初始化
34
+ ## 快速开始
64
35
 
65
- ```typescript
66
- import { MedViewerEngine } from './core/Engine' // 以本地路径为例
67
- import OpenSeadragon from 'openseadragon'
36
+ ### 原生 HTML / UMD
68
37
 
69
- const viewerElement = document.getElementById('med-viewer-container')
38
+ ```html
39
+ <!DOCTYPE html>
40
+ <html>
41
+ <head>
42
+ <link rel="stylesheet" href="https://unpkg.com/med-viewer-sdk/dist/style.css">
43
+ </head>
44
+ <body>
45
+ <div id="viewer" style="width:100vw;height:100vh;"></div>
70
46
 
71
- if (viewerElement) {
72
- const engine = new MedViewerEngine({
73
- element: viewerElement,
74
- viewerOptions: {
75
- // OpenSeadragon 选项
76
- id: 'openseadragon-viewer',
77
- prefixUrl: 'https://openseadragon.github.io/openseadragon/images/',
78
- tileSources: {
79
- type: 'image',
80
- url: 'https://openseadragon.github.io/example-images/duomo/duomo.dzi'
81
- }
82
- // ... 其他 OSD 选项
83
- },
84
- plugins: {
85
- toolbar: true, // 启用默认工具栏
86
- selection: true, // 启用选择插件
87
- scalebar: {
88
- // 启用比例尺插件并带自定义选项
89
- type: 'MICROSCOPY',
90
- location: 'BOTTOM_LEFT',
91
- color: 'rgb(255, 255, 255)',
92
- fontColor: 'rgb(255, 255, 255)',
93
- backgroundColor: 'rgba(0, 0, 0, 0.5)'
94
- },
95
- anno: true, // 启用 Annotorious
96
- konva: true, // 启用 Konva.js 绘图
97
- colorAdjust: {
98
- // 启用颜色调整并带初始设置
99
- initial: {
100
- brightness: 1.2,
101
- contrast: 0.8,
102
- invert: true
47
+ <script src="https://unpkg.com/openseadragon"></script>
48
+ <script src="https://unpkg.com/med-viewer-sdk"></script>
49
+ <script>
50
+ const engine = new MedViewerSDK.MedViewerEngine({
51
+ osdOptions: {
52
+ id: 'viewer',
53
+ prefixUrl: 'https://openseadragon.github.io/openseadragon/images/',
54
+ tileSources: {
55
+ type: 'image',
56
+ url: './slide.dzi'
103
57
  }
58
+ },
59
+ locale: 'zh-CN',
60
+ plugins: {
61
+ toolbar: true,
62
+ annotorious: {
63
+ onCreateAnnotation: (anno) => console.log('新建标注', anno)
64
+ },
65
+ selection: {
66
+ onSelection: (rect, blob) => {
67
+ if (blob) console.log('截图完成', rect, blob)
68
+ }
69
+ },
70
+ colorAdjust: true,
71
+ scalebar: { pixelsPerMeter: 100000 },
72
+ magnification: true
104
73
  }
105
- }
106
- })
74
+ })
75
+ </script>
76
+ </body>
77
+ </html>
78
+ ```
107
79
 
108
- // 访问插件
109
- if (engine.toolbar) {
110
- console.log('工具栏已激活')
111
- }
112
- if (engine.selection) {
113
- engine.selection.enable()
114
- engine.selection.setSelectionMode('RECTANGLE')
80
+ ### ES Module
81
+
82
+ ```ts
83
+ import { MedViewerEngine, ToolbarPosition } from 'med-viewer-sdk'
84
+ import 'med-viewer-sdk/dist/style.css'
85
+
86
+ const engine = new MedViewerEngine({
87
+ osdOptions: {
88
+ id: 'viewer',
89
+ tileSources: 'https://example.com/slide.dzi'
90
+ },
91
+ plugins: {
92
+ toolbar: { position: ToolbarPosition.BOTTOM_CENTER },
93
+ annotorious: true,
94
+ colorAdjust: true
115
95
  }
116
- if (engine.anno) {
117
- engine.anno.setEnabled(true)
118
- engine.anno.setTool('rect')
96
+ })
97
+ ```
98
+
99
+ ### Vue 2 / Vue 3
100
+
101
+ ```vue
102
+ <template>
103
+ <MedViewer :options="viewerOptions" @ready="onReady" />
104
+ </template>
105
+
106
+ <script>
107
+ import MedViewer from 'med-viewer-sdk/dist/vue'
108
+ import 'med-viewer-sdk/dist/style.css'
109
+
110
+ export default {
111
+ components: { MedViewer },
112
+ data() {
113
+ return {
114
+ viewerOptions: {
115
+ osdOptions: {
116
+ id: 'my-viewer',
117
+ tileSources: '/slide.dzi'
118
+ },
119
+ locale: 'zh-CN',
120
+ plugins: {
121
+ toolbar: true,
122
+ annotorious: true,
123
+ colorAdjust: true,
124
+ selection: true,
125
+ scalebar: { pixelsPerMeter: 100000 },
126
+ magnification: true
127
+ }
128
+ }
129
+ }
130
+ },
131
+ methods: {
132
+ onReady(engine) {
133
+ // engine 即为 MedViewerEngine 实例
134
+ console.log('引擎就绪', engine)
135
+ }
119
136
  }
120
- if (engine.konva) {
121
- engine.konva.setEnabled(true)
122
- engine.konva.setTool('rect')
137
+ }
138
+ </script>
139
+ ```
140
+
141
+ > Vue 组件在 `onMounted` 时创建引擎,`onBeforeUnmount` 时自动销毁,无需手动管理。
142
+
143
+ ---
144
+
145
+ ## 引擎配置
146
+
147
+ ### MedEngineOptions
148
+
149
+ ```ts
150
+ interface MedEngineOptions {
151
+ osdOptions: OpenSeadragon.Options // 必填,OpenSeadragon 配置
152
+ locale?: 'zh-CN' | 'en-US' // 国际化语言,默认 'zh-CN'
153
+ plugins?: {
154
+ annotorious?: boolean | AnnotoriousOptions
155
+ toolbar?: boolean | ToolbarOptions
156
+ colorAdjust?: boolean | ColorAdjustOptions
157
+ selection?: boolean | SelectionOptions
158
+ scalebar?: boolean | ScalebarOptions
159
+ magnification?: boolean | MagnificationOptions
123
160
  }
124
- if (engine.colorAdjust) {
125
- engine.colorAdjust.setAdjustments({ brightness: 1.5 })
161
+ }
162
+ ```
163
+
164
+ > 传 `true` 等同于传 `{}`(使用默认配置)。
165
+
166
+ ### Engine 公开属性
167
+
168
+ 创建后可通过 `engine.xxx` 访问各插件实例:
169
+
170
+ | 属性 | 类型 | 说明 |
171
+ |---|---|---|
172
+ | `engine.viewer` | `OpenSeadragon.Viewer` | 底层 OSD 查看器 |
173
+ | `engine.anno` | `AnnoAnnotator \| null` | 标注插件 |
174
+ | `engine.toolbar` | `MedToolbar \| null` | 工具栏插件 |
175
+ | `engine.colorAdjust` | `ColorAdjustPlugin \| null` | 颜色调整插件 |
176
+ | `engine.selection` | `SelectionPlugin \| null` | 截图插件 |
177
+ | `engine.scalebar` | `ScalebarPlugin \| null` | 比例尺插件 |
178
+ | `engine.magnification` | `MagnificationPlugin \| null` | 放大镜插件 |
179
+
180
+ ### Engine 事件
181
+
182
+ ```ts
183
+ engine.addHandler('ready', () => {
184
+ console.log('图像首次加载完成')
185
+ })
186
+ ```
187
+
188
+ ---
189
+
190
+ ## 插件详解
191
+
192
+ ### 1. 标注插件 (Annotorious)
193
+
194
+ 提供六种标注工具:矩形、多边形、圆形、椭圆、线段、手绘。
195
+
196
+ #### 配置
197
+
198
+ ```ts
199
+ interface AnnotoriousOptions {
200
+ onCreateAnnotation?: (annotation: any) => void
201
+ onUpdateAnnotation?: (annotation: any, previous: any) => void
202
+ onDeleteAnnotation?: (annotation: any) => void
203
+ onCancelAnnotation?: (annotation: any) => void
204
+ locale?: string // 默认跟随引擎 locale
205
+ options?: {
206
+ formatter?: any // 标注格式化器
126
207
  }
208
+ }
209
+ ```
210
+
211
+ #### API
212
+
213
+ ```ts
214
+ const anno = engine.anno
215
+
216
+ // 设置工具
217
+ anno.setTool('rect', '#ff0000') // 启用矩形标注,颜色红色
218
+ anno.setTool('polygon', '#00ff00') // 启用多边形标注
219
+ anno.setTool(null) // 关闭标注模式
220
+
221
+ // 启用/禁用
222
+ anno.setEnabled(true)
223
+ anno.setEnabled(false)
224
+
225
+ // 数据操作
226
+ anno.getAnnotations() // 获取所有标注
227
+ anno.setAnnotations([...]) // 加载标注数据
228
+ anno.clear() // 清除所有标注
229
+
230
+ // 事件监听
231
+ anno.on('modeChange', (state) => {
232
+ console.log(state.enabled, state.tool)
233
+ })
234
+ ```
235
+
236
+ #### 事件
237
+
238
+ | 事件名 | 参数 | 说明 |
239
+ |---|---|---|
240
+ | `modeChange` | `{ enabled: boolean, tool: string \| null }` | 标注模式变化 |
241
+
242
+ ---
127
243
 
128
- // 不再需要时进行清理
129
- // engine.destroy();
244
+ ### 2. 截图插件 (Selection)
245
+
246
+ 框选图像区域并导出为 Blob,支持旋转和像素坐标。
247
+
248
+ #### 配置
249
+
250
+ ```ts
251
+ interface SelectionOptions {
252
+ showSelectionControl?: boolean // 是否显示控件按钮,默认 true
253
+ showConfirmDenyButtons?: boolean // 是否显示确认/取消按钮,默认 true
254
+ returnPixelCoordinates?: boolean // 返回像素坐标,默认 true
255
+ keyboardShortcut?: string // 快捷键,默认 'c'
256
+ allowRotation?: boolean // 允许旋转选区,默认 true
257
+ restrictToImage?: boolean // 限制在图像内,默认 false
258
+ onSelection?: (rect: Rect, blob: Blob \| null) => void // 确认选区回调
259
+ onSelectionCanceled?: () => void // 取消选区回调
130
260
  }
131
261
  ```
132
262
 
133
- ### 自定义工具栏
263
+ #### API
134
264
 
135
- 您可以通过将 `ToolbarButton` 配置数组传递给 `toolbar` 插件选项来定制工具栏。可以通过匹配其 `id` 来覆盖现有默认按钮。
265
+ ```ts
266
+ const sel = engine.selection
136
267
 
137
- ```typescript
138
- import { MedViewerEngine, ToolbarButton } from './core/Engine' // 以本地路径为例
139
- import myCustomIcon from './assets/my-icon.png'
268
+ sel.enable() // 启用选择模式
269
+ sel.disable() // 禁用选择模式
270
+ sel.toggleState() // 切换选择模式
271
+ sel.isEnabled() // 查询是否启用
272
+ sel.getSelection() // 获取当前选区
273
+ sel.clearSelection() // 清除选区
140
274
 
141
- const customToolbarButtons: ToolbarButton[] = [
142
- {
143
- id: 'anno', // 覆盖默认的 'anno' 按钮
144
- label: '我的标注',
145
- icon: myCustomIcon // 使用自定义图标
146
- // 保留原始的 dropdownContent 或定义新的
147
- },
148
- {
149
- id: 'customTool', // 添加新的自定义按钮
150
- label: '新工具',
151
- onClick: (engine) => {
152
- alert('自定义工具已点击!')
153
- // 在此处实现自定义逻辑
154
- }
155
- }
156
- ]
275
+ // 事件监听
276
+ sel.on('selectionEnabled', (enabled: boolean) => {
277
+ console.log('选择模式', enabled ? '开启' : '关闭')
278
+ })
279
+ ```
157
280
 
158
- const engine = new MedViewerEngine({
159
- // ...
160
- plugins: {
161
- toolbar: {
162
- buttons: customToolbarButtons
163
- // ... 其他工具栏选项
164
- }
165
- // ... 其他插件
281
+ #### 事件
282
+
283
+ | 事件名 | 参数 | 说明 |
284
+ |---|---|---|
285
+ | `selectionEnabled` | `boolean` | 选择模式启用/禁用 |
286
+ | `selectionStateToggled` | `boolean` | 选择模式切换 |
287
+
288
+ ---
289
+
290
+ ### 3. 颜色调整插件 (ColorAdjust)
291
+
292
+ 基于 WebGL 着色器的实时图像处理,内置防抖优化。
293
+
294
+ #### 配置
295
+
296
+ ```ts
297
+ interface ColorAdjustOptions {
298
+ adjustments?: ColorAdjustments // 初始调整值
299
+ debounceMs?: number // 防抖延迟,默认 60
300
+ loadMode?: 'async' | 'sync' // 加载模式,默认 'async'
301
+ onAdjustmentsChange?: (adj: ColorAdjustments) => void
302
+ }
303
+
304
+ interface ColorAdjustments {
305
+ brightness?: number // 亮度 0~2,默认 1
306
+ contrast?: number // 对比度 0~2,默认 1
307
+ saturation?: number // 饱和度 0~3,默认 1
308
+ gamma?: number // 伽马 0.1~3,默认 1
309
+ hue?: number // 色相 0~360,默认 0
310
+ invert?: boolean // 反色
311
+ sepia?: boolean // 怀旧
312
+ greyscale?: boolean // 灰度
313
+ }
314
+ ```
315
+
316
+ #### API
317
+
318
+ ```ts
319
+ const ca = engine.colorAdjust
320
+
321
+ ca.setAdjustments({ brightness: 1.5, contrast: 1.2 })
322
+ ca.setAdjustments({ greyscale: true })
323
+ ca.adjustments // 获取当前调整值
324
+ ca.reset() // 重置为默认值
325
+ ```
326
+
327
+ ---
328
+
329
+ ### 4. 比例尺插件 (Scalebar)
330
+
331
+ 在图像上叠加比例尺标注。
332
+
333
+ #### 配置
334
+
335
+ ```ts
336
+ interface ScalebarOptions {
337
+ type?: ScalebarType // NONE=0, MICROSCOPY=1, MAP=2
338
+ pixelsPerMeter?: number // 每米像素数
339
+ location?: ScalebarLocation // NONE=0, TOP_LEFT=1, TOP_RIGHT=2, BOTTOM_RIGHT=3, BOTTOM_LEFT=4
340
+ color?: string
341
+ fontColor?: string
342
+ backgroundColor?: string
343
+ fontSize?: string
344
+ barThickness?: number
345
+ minWidth?: string
346
+ }
347
+ ```
348
+
349
+ #### 示例
350
+
351
+ ```ts
352
+ plugins: {
353
+ scalebar: {
354
+ type: ScalebarType.MICROSCOPY,
355
+ pixelsPerMeter: 100000,
356
+ location: ScalebarLocation.BOTTOM_LEFT
166
357
  }
167
- })
358
+ }
168
359
  ```
169
360
 
170
- ### 在 Vue 项目中使用
361
+ ---
171
362
 
172
- `med-viewer-sdk` 可以在 Vue 2 或 Vue 3 项目中使用。由于 `vue` 是 `med-viewer-sdk` 的一个 `peerDependency`,您需要确保您的项目中已经安装了 `vue`。
363
+ ### 5. 放大镜插件 (Magnification)
173
364
 
174
- #### 1. 安装依赖
365
+ 显示当前放大倍率并提供快捷缩放按钮。
175
366
 
176
- 在您的 Vue 项目中安装 `med-viewer-sdk` 及其 `peerDependencies`。
367
+ #### 配置
177
368
 
178
- ```bash
179
- npm install med-viewer-sdk openseadragon vue # 根据您的 Vue 版本安装相应的 Vue 包
180
- # 或者使用 yarn
181
- yarn add med-viewer-sdk openseadragon vue
369
+ ```ts
370
+ interface MagnificationOptions {
371
+ type?: MagnificationType // 'LD' 或 'OSD',默认 'OSD'
372
+ position?: MagnificationPosition // 位置,默认 'MIDDLE_LEFT'
373
+ offsetX?: number
374
+ offsetY?: number
375
+ pixelsPerMeter?: number // LD 模式需要
376
+ }
377
+ ```
378
+
379
+ #### API
380
+
381
+ ```ts
382
+ const mag = engine.magnification
383
+ mag.getMagnification() // 获取当前倍率
384
+ mag.show() // 显示
385
+ mag.hide() // 隐藏
386
+ mag.toggle() // 切换可见性
387
+ mag.refresh() // 刷新显示
182
388
  ```
183
389
 
184
- #### 2. 创建 Vue 组件
390
+ ---
185
391
 
186
- 创建一个 Vue 组件来封装 `MedViewerEngine` 的实例化和生命周期管理。
392
+ ## 工具栏
187
393
 
188
- **Vue 3 (Composition API):**
394
+ ### 内置工具栏
189
395
 
190
- ```vue
191
- <template>
192
- <div ref="viewerContainer" class="med-viewer-container"></div>
193
- </template>
396
+ ```ts
397
+ plugins: {
398
+ toolbar: true // 使用默认工具栏(重置、标注、颜色调整、截图)
399
+ }
400
+ ```
194
401
 
195
- <script setup lang="ts">
196
- import { ref, onMounted, onBeforeUnmount } from 'vue'
197
- import { MedViewerEngine } from 'med-viewer-sdk'
198
- import OpenSeadragon from 'openseadragon' // 如果需要 OpenSeadragon 类型
402
+ ### 自定义位置
199
403
 
200
- const viewerContainer = ref<HTMLElement | null>(null)
201
- let medViewer: MedViewerEngine | null = null
404
+ ```ts
405
+ import { ToolbarPosition } from 'med-viewer-sdk'
202
406
 
203
- onMounted(() => {
204
- if (viewerContainer.value) {
205
- medViewer = new MedViewerEngine({
206
- element: viewerContainer.value,
207
- viewerOptions: {
208
- id: 'openseadragon-viewer',
209
- prefixUrl: 'https://openseadragon.github.io/openseadragon/images/',
210
- tileSources: {
211
- type: 'image',
212
- url: 'https://openseadragon.github.io/example-images/duomo/duomo.dzi'
407
+ plugins: {
408
+ toolbar: {
409
+ position: ToolbarPosition.BOTTOM_CENTER
410
+ }
411
+ }
412
+ ```
413
+
414
+ 可选位置:`TOP_LEFT` `TOP_CENTER` `TOP_RIGHT` `BOTTOM_LEFT` `BOTTOM_CENTER` `BOTTOM_RIGHT` `MIDDLE_LEFT` `MIDDLE_RIGHT`
415
+
416
+ ### 自定义按钮
417
+
418
+ 通过 `buttons` 配置完全控制工具栏按钮,ID 匹配内置按钮时会合并默认配置:
419
+
420
+ ```ts
421
+ plugins: {
422
+ toolbar: {
423
+ position: ToolbarPosition.BOTTOM_RIGHT,
424
+ buttons: [
425
+ {
426
+ id: 'reset', // 匹配内置 reset 按钮,覆盖默认配置
427
+ icon: myResetIcon,
428
+ label: '回到原点',
429
+ onClick: (engine, hide) => {
430
+ engine.viewer.viewport.goHome()
431
+ hide()
213
432
  }
214
433
  },
215
- plugins: {
216
- toolbar: true,
217
- selection: true,
218
- scalebar: {
219
- type: 'MICROSCOPY',
220
- location: 'BOTTOM_LEFT',
221
- color: 'rgb(255, 255, 255)',
222
- fontColor: 'rgb(255, 255, 255)',
223
- backgroundColor: 'rgba(0, 0, 0, 0.5)'
224
- },
225
- anno: true,
226
- konva: true,
227
- colorAdjust: {
228
- initial: {
229
- brightness: 1.2,
230
- contrast: 0.8,
231
- invert: true
232
- }
434
+ {
435
+ id: 'anno' // 匹配内置 anno 按钮,使用默认 dropdownContent
436
+ },
437
+ {
438
+ id: 'colorAdjust' // 匹配内置 colorAdjust 按钮
439
+ },
440
+ {
441
+ id: 'selection' // 匹配内置 selection 按钮
442
+ },
443
+ // 添加自定义按钮
444
+ {
445
+ id: 'myTool',
446
+ icon: myToolIcon,
447
+ label: '我的工具',
448
+ onClick: (engine, hide) => {
449
+ console.log('自定义工具被点击')
450
+ hide()
233
451
  }
234
452
  }
235
- })
236
-
237
- // 可以访问插件并进行操作
238
- if (medViewer.selection) {
239
- medViewer.selection.enable()
240
- medViewer.selection.setSelectionMode('RECTANGLE')
241
- }
453
+ ]
242
454
  }
243
- })
455
+ }
456
+ ```
244
457
 
245
- onBeforeUnmount(() => {
246
- if (medViewer) {
247
- medViewer.destroy()
248
- medViewer = null
249
- }
250
- })
251
- </script>
458
+ ### 按钮激活态
252
459
 
253
- <style scoped>
254
- .med-viewer-container {
255
- width: 100%;
256
- height: 80vh; /* 根据需要调整高度 */
257
- background-color: #000;
258
- }
259
- </style>
460
+ 按钮激活时显示与 hover 相同的高亮效果(绿色背景),支持三种方式:
461
+
462
+ #### 方式一:命令式 — `setButtonActive`
463
+
464
+ 最灵活,外部代码随时调用:
465
+
466
+ ```ts
467
+ // 激活
468
+ engine.toolbar.setButtonActive('myTool', true)
469
+ // 取消激活
470
+ engine.toolbar.setButtonActive('myTool', false)
260
471
  ```
261
472
 
262
- **Vue 2 (Options API):**
473
+ #### 方式二:声明式 `activeEvent`
263
474
 
264
- ```vue
265
- <template>
266
- <div ref="viewerContainer" class="med-viewer-container"></div>
267
- </template>
475
+ 在按钮配置中声明事件源,Toolbar 自动绑定监听,事件触发时自动更新激活态:
268
476
 
269
- <script lang="ts">
270
- import Vue from 'vue'
271
- import { MedViewerEngine } from 'med-viewer-sdk'
272
- import OpenSeadragon from 'openseadragon' // 如果需要 OpenSeadragon 类型
477
+ ```ts
478
+ {
479
+ id: 'myTool',
480
+ icon: myToolIcon,
481
+ label: '我的工具',
482
+ onClick: (engine, hide) => { /* ... */ },
483
+ activeEvent: {
484
+ emitter: engine.anno, // 任何有 .on() 方法的对象
485
+ event: 'modeChange', // 监听的事件名
486
+ mapToActive: (data) => data.enabled // 将事件数据映射为 boolean
487
+ }
488
+ }
489
+ ```
273
490
 
274
- export default Vue.extend({
275
- data() {
276
- return {
277
- medViewer: null as MedViewerEngine | null
278
- }
279
- },
280
- mounted() {
281
- if (this.$refs.viewerContainer) {
282
- this.medViewer = new MedViewerEngine({
283
- element: this.$refs.viewerContainer as HTMLElement,
284
- viewerOptions: {
285
- id: 'openseadragon-viewer',
286
- prefixUrl: 'https://openseadragon.github.io/openseadragon/images/',
287
- tileSources: {
288
- type: 'image',
289
- url: 'https://openseadragon.github.io/example-images/duomo/duomo.dzi'
290
- }
291
- },
292
- plugins: {
293
- toolbar: true,
294
- selection: true,
295
- scalebar: {
296
- type: 'MICROSCOPY',
297
- location: 'BOTTOM_LEFT',
298
- color: 'rgb(255, 255, 255)',
299
- fontColor: 'rgb(255, 255, 255)',
300
- backgroundColor: 'rgba(0, 0, 0, 0.5)'
301
- },
302
- anno: true,
303
- konva: true,
304
- colorAdjust: {
305
- initial: {
306
- brightness: 1.2,
307
- contrast: 0.8,
308
- invert: true
309
- }
310
- }
311
- }
312
- })
491
+ #### 方式三:下拉框联动 — `activeOnDropdown`
313
492
 
314
- if (this.medViewer.selection) {
315
- this.medViewer.selection.enable()
316
- this.medViewer.selection.setSelectionMode('RECTANGLE')
317
- }
318
- }
493
+ 下拉框按钮设为 `true`,下拉框打开自动激活、关闭自动取消:
494
+
495
+ ```ts
496
+ {
497
+ id: 'myPanel',
498
+ icon: myPanelIcon,
499
+ label: '我的面板',
500
+ dropdownContent: (engine, hide) => {
501
+ const el = document.createElement('div')
502
+ el.textContent = '面板内容'
503
+ return el
319
504
  },
320
- beforeDestroy() {
321
- // Vue 2 使用 beforeDestroy
322
- if (this.medViewer) {
323
- this.medViewer.destroy()
324
- this.medViewer = null
505
+ activeOnDropdown: true
506
+ }
507
+ ```
508
+
509
+ #### 内置按钮激活机制
510
+
511
+ | 按钮 | 激活来源 | 机制 |
512
+ |---|---|---|
513
+ | `anno` | `engine.anno` 的 `modeChange` 事件 | 自动监听 |
514
+ | `selection` | `engine.selection` 的 `selectionEnabled` 事件 | 自动监听 |
515
+ | `colorAdjust` | 下拉框开闭 | `activeOnDropdown: true` |
516
+ | `reset` | 无 | 不激活 |
517
+
518
+ ### 自定义下拉面板
519
+
520
+ 任何按钮都可以配置 `dropdownContent`,返回一个 DOM 元素:
521
+
522
+ ```ts
523
+ {
524
+ id: 'filters',
525
+ icon: filterIcon,
526
+ label: '滤镜',
527
+ activeOnDropdown: true,
528
+ dropdownContent: (engine, hide) => {
529
+ const container = document.createElement('div')
530
+ container.className = 'med-toolbar-dropdown-inner'
531
+
532
+ const btn = document.createElement('button')
533
+ btn.className = 'med-tool-item'
534
+ btn.textContent = '模糊'
535
+ btn.onclick = () => {
536
+ // 应用滤镜...
537
+ hide() // 关闭下拉面板
325
538
  }
326
- }
327
- })
328
- </script>
329
539
 
330
- <style scoped>
331
- .med-viewer-container {
332
- width: 100%;
333
- height: 80vh; /* 根据需要调整高度 */
334
- background-color: #000;
540
+ container.appendChild(btn)
541
+ return container
542
+ }
335
543
  }
336
- </style>
337
544
  ```
338
545
 
339
- #### 3. 注意事项
546
+ > `hide()` 用于关闭当前下拉面板,务必在操作完成后调用。
340
547
 
341
- - **CSS 导入**:如果 `med-viewer-sdk` 包含任何 CSS 样式,您可能需要在您的 Vue 项目的入口文件或相关组件中导入它。例如:`import 'med-viewer-sdk/dist/style.css';`
342
- - **全局样式**:确保 `med-viewer-sdk` 的容器元素有足够的宽高,以便查看器能够正确渲染。
343
- - **响应式数据**:`MedViewerEngine` 实例本身不是响应式的。如果您需要其内部状态在 Vue 中响应式,您可能需要手动将其属性或方法包装在 Vue 的响应式系统中。
548
+ ---
344
549
 
345
- ## 引用方式
550
+ ## Engine 常用 API
346
551
 
347
- 构建完成后,您可以通过以下方式在其他项目中使用 `med-viewer-sdk`:
552
+ ### 图像导航
348
553
 
349
- ### 1. 本地开发(使用 `npm link`)
554
+ ```ts
555
+ engine.viewer.viewport.goHome() // 回到初始视图
556
+ engine.viewer.viewport.zoomTo(2) // 缩放到指定级别
557
+ engine.viewer.viewport.panTo(new OpenSeadragon.Point(0.5, 0.5)) // 平移到指定位置
558
+ ```
350
559
 
351
- 如果您在本地同时开发 `med-viewer-sdk` 和另一个项目,`npm link` 是一个便捷的选择。
560
+ ### 跳转到指定位置
352
561
 
353
- - **在 `med-viewer-sdk` 项目目录中执行:**
354
- ```bash
355
- npm link
356
- ```
357
- - **在您的其他项目目录中执行:**
358
- ```bash
359
- npm link med-viewer-sdk
360
- ```
361
- 现在,您就可以像从 npm 安装一样导入 `med-viewer-sdk` 了。
562
+ ```ts
563
+ // 以指定倍率跳转到图像坐标 (x, y)
564
+ await engine.goToPosition({ x: 1000, y: 2000 }, true, 20)
565
+ // 参数: target坐标, 是否动画, 目标倍率(mag)
566
+ // mag=null 时仅平移,不缩放
567
+ ```
362
568
 
363
- ### 2. 从本地路径安装
569
+ ### AI 标注框
364
570
 
365
- 您可以直接从文件系统的本地路径安装打包后的 SDK。
571
+ ```ts
572
+ // 加载 AI 检测框
573
+ engine.loadAIMarks([
574
+ {
575
+ x: 100, y: 200, width: 50, height: 50,
576
+ style: { border: '2px solid red' },
577
+ labels: [
578
+ { label: '类型', value: '肿瘤', style: { color: '#333', fontSize: 12 } }
579
+ ]
580
+ }
581
+ ], true) // true = 显示标签
366
582
 
367
- - **在您的其他项目的 `package.json` 中添加:**
368
- ```json
369
- "dependencies": {
370
- "med-viewer-sdk": "file:../path/to/your/med-viewer-sdk", // 根据实际路径调整
371
- // ... 其他依赖
583
+ // 更新
584
+ engine.updateAIMarks(newBoxes, showLabel)
585
+
586
+ // 清除
587
+ engine.clearAIMarks()
588
+ ```
589
+
590
+ ### 选区框
591
+
592
+ ```ts
593
+ engine.loadSelectionBox([
594
+ {
595
+ x: 100, y: 200, width: 50, height: 50,
596
+ style: { border: '2px solid #4CAF50' }
372
597
  }
373
- ```
374
- - **然后在您的其他项目目录中运行 `npm install`。**
375
-
376
- ### 3. 发布到包注册表 (例如 npm)
377
-
378
- 如果这是一个可重用的库,您通常会将其发布到包注册表。
379
-
380
- - **确保您的 `package.json` 已准备好发布:**
381
- - `name`、`version`、`main`、`module`、`types`、`files` 字段应正确配置。
382
- - `files` 数组应包含 `dist` 目录和任何其他必要文件。
383
- - **登录 npm (如果尚未登录):**
384
- ```bash
385
- npm login
386
- ```
387
- - **发布:**
388
- ```bash
389
- npm publish --access public // 如果是私有包,则无需 --access public
390
- ```
391
-
392
- ### 4. 在您的代码中导入
393
-
394
- 安装/链接后,您可以在应用程序中导入它:
395
-
396
- - **对于 ES 模块 (推荐用于现代 JS/TS 项目):**
397
- ```typescript
398
- import { MedViewerEngine } from 'med-viewer-sdk'
399
- // 或者如果您在脚本标签中需要全局名称:
400
- // const MedViewerSDK = window.MedViewerSDK;
401
- ```
402
- - **对于 CommonJS (如果使用 Node.js 或旧版打包工具):**
403
- ```javascript
404
- const { MedViewerEngine } = require('med-viewer-sdk')
405
- ```
406
- - **直接在 HTML (UMD 构建):**
407
- ```html
408
- <script src="path/to/your/node_modules/med-viewer-sdk/dist/med-viewer-sdk.umd.js"></script>
409
- <script>
410
- const MedViewerSDK = window.MedViewerSDK
411
- // 使用 MedViewerSDK.MedViewerEngine
412
- </script>
413
- ```
598
+ ])
599
+ ```
600
+
601
+ ### 语言切换
602
+
603
+ ```ts
604
+ engine.setLocale('en-US') // 动态切换为英文
605
+ engine.setLocale('zh-CN') // 切换为中文
606
+ ```
607
+
608
+ ### 销毁
609
+
610
+ ```ts
611
+ engine.destroy() // 销毁所有插件和 viewer
612
+ ```
613
+
614
+ ---
615
+
616
+ ## 国际化
617
+
618
+ 内置中文 (`zh-CN`) 和英文 (`en-US`) 两种语言:
619
+
620
+ | 键 | 中文 | 英文 |
621
+ |---|---|---|
622
+ | toolbar.annoColor | 标注颜色 | Annotation Color |
623
+ | toolbar.annoShape | 标注形状 | Annotation Shape |
624
+ | toolbar.rect | 矩形 | Rectangle |
625
+ | toolbar.polygon | 多边形 | Polygon |
626
+ | toolbar.circle | 圆形 | Circle |
627
+ | toolbar.ellipse | 椭圆 | Ellipse |
628
+ | toolbar.line | 线段 | Line |
629
+ | toolbar.freehand | 手绘 | Freehand |
630
+ | toolbar.reset | 重置 | Reset |
631
+ | toolbar.screenshot | 截图 | Screenshot |
632
+ | toolbar.brightness | 亮度 | Brightness |
633
+ | toolbar.contrast | 对比度 | Contrast |
634
+ | toolbar.saturation | 饱和度 | Saturation |
635
+ | toolbar.gamma | 伽马 | Gamma |
636
+ | toolbar.hue | 色相 | Hue |
637
+ | toolbar.invert | 反色 | Invert |
638
+ | toolbar.sepia | 怀旧 | Sepia |
639
+ | toolbar.greyscale | 灰度 | Greyscale |
640
+
641
+ ---
642
+
643
+ ## ToolbarButton 接口
644
+
645
+ ```ts
646
+ interface ToolbarButton {
647
+ id: string // 按钮唯一标识
648
+ label?: string // 提示文字
649
+ icon?: string // 图标 URL
650
+ dropdownContent?: (engine, hide) => HTMLElement // 下拉面板内容
651
+ onClick?: (engine, hide) => void // 点击回调
652
+ activeEvent?: { // 声明式激活状态
653
+ emitter: any // 事件发射器(需有 .on())
654
+ event: string // 事件名
655
+ mapToActive: (data: any) => boolean // 事件数据映射
656
+ }
657
+ activeOnDropdown?: boolean // 下拉框开闭时自动激活
658
+ }
659
+ ```
660
+
661
+ ---
662
+
663
+ ## 构建与开发
664
+
665
+ ```bash
666
+ # 安装依赖
667
+ npm install
668
+
669
+ # 构建(生成 dist/ 目录)
670
+ npm run build
671
+
672
+ # 输出格式
673
+ # dist/med-viewer-sdk.umd.js — UMD 格式(<script> 标签引入)
674
+ # dist/med-viewer-sdk.mjs — ESM 格式(import 引入)
675
+ # dist/med-viewer-sdk.d.ts — TypeScript 类型声明
676
+ # dist/style.css — 样式文件
677
+ ```
678
+
679
+ ---
680
+
681
+ ## 浏览器兼容性
414
682
 
415
- ## API 参考
683
+ | 浏览器 | 版本 |
684
+ |---|---|
685
+ | Chrome | 80+ |
686
+ | Firefox | 80+ |
687
+ | Safari | 14+ |
688
+ | Edge | 80+ |
416
689
 
417
- (此处将提供 `MedViewerEngine`、`Toolbar`、`SelectionPlugin`、`ScalebarPlugin`、`AnnoAnnotator`、`KonvaAnnotator`、`ColorAdjustPlugin` 及其选项的详细 API 参考。这通常从 JSDoc 或单独的文档生成。)
690
+ > 需要 WebGL 支持以使用颜色调整功能。
418
691
 
419
- ## 开发
692
+ ---
420
693
 
421
- (有关设置开发环境、运行测试、构建等的说明。)
694
+ ## 依赖说明
422
695
 
423
- ## 贡献
696
+ | 依赖 | 用途 |
697
+ |---|---|
698
+ | [openseadragon](https://openseadragon.github.io/) | 深度缩放图像渲染引擎 |
699
+ | [annotorious-openseadragon-ld](https://www.npmjs.com/package/annotorious-openseadragon-ld) | Annotorious 标注库(定制版) |
700
+ | [openseadragon-filtering](https://www.npmjs.com/package/openseadragon-filtering) | OSD 瓦片滤镜处理器 |
701
+ | [svg-path-properties](https://www.npmjs.com/package/svg-path-properties) | SVG 路径计算(标注测量) |
424
702
 
425
- (贡献项目的指南。)
703
+ ---
426
704
 
427
- ## 许可证
705
+ ## License
428
706
 
429
- (许可证信息。)
707
+ MIT