MineImages — Obsidian 统一预览插件开发纪实

一、开发背景

1.1 痛点

Obsidian 作为一款优秀的本地知识库工具,在图片和 Mermaid 图表预览方面存在明显的交互短板:

  • 图片预览:原生仅支持点击后在新标签页打开,无法在上下文中缩放、旋转或对比查看多张图片
  • Mermaid 图表:渲染后尺寸不可控,大图溢出容器,小图留白过多;编辑模式下无法直接预览
  • 功能碎片化:社区中虽有一些独立插件,但各自解决单一问题,交互风格不统一且存在功能重叠

1.2 设计目标

开发一款统一、流畅、功能完整的预览插件,满足以下设计原则:

统一

图片 + Mermaid 同一浮层

流畅

≤500ms 打开

60fps 缩放平移

完整

缩放/旋转/复制/切换

标注/全屏/缩略图导航

一站式预览体验

1.3 技术选型

秉持 “最大化利用 Obsidian 官方 API,避免重复造轮子” 的原则:

模块 选用方案 原因
预览容器 Modal Obsidian 官方推荐,自带遮罩和关闭逻辑
图表捕获(阅读模式) MarkdownPostProcessor 原生渲染管道,无需额外渲染
图表捕获(实时预览) DOM 事件委托 兼容 .cm-embed-block 中的动态渲染
图片捕获 registerDomEvent 轻量级,无侵入
变换(缩放/旋转/平移) CSS transform GPU 加速,60fps
右键菜单 Menu 原生 Obsidian 风格
设置界面 PluginSettingTab 标准配置模式
主题适配 CSS 变量 自动跟随深浅主题
国际化 i18n.ts + as const 推导 中英双语 55 个 key,设置页实时切换

二、功能介绍

2.1 核心预览能力

点击笔记中的任意图片或 Mermaid 图表,立即在统一的模态浮层中打开:

"工具栏" "mineImages 浮层" "笔记页面" "工具栏" "mineImages 浮层" "笔记页面" User "点击图片/Mermaid" "收集当前文件所有预览项" "渲染内容(img / SVG)" "显示工具栏" "缩放 / 旋转 / 复制 / 切换" "点击缩放" "CSS transform 缩放" "实时响应" "点击标注" "启用 Canvas 标注层" "可绘制画笔/箭头/矩形" User

在这里插入图片描述

2.2 交互功能矩阵

功能 触发方式 说明
缩放 Ctrl + 滚轮 / 工具栏 ± 按钮 步进可配置,范围 10%–1000%
拖动平移 鼠标拖拽 缩放后平移查看细节
旋转 工具栏按钮 / R 键 90° 步进
重置 双击内容 / 工具栏按钮 / 0 键 恢复初始缩放和旋转
复制 工具栏按钮 / 右键菜单 图片/Mermaid 均复制为 PNG
切换 ← → 箭头键 / 工具栏 / 右键菜单 遍历当前文件所有预览项
关闭 ESC / 点击遮罩 / 工具栏关闭按钮
全屏 工具栏按钮 浏览器 Fullscreen API
标注 工具栏笔/箭头/矩形/清除 Canvas 叠加层,不修改原图
缩略图导航 左侧面板 固定大小的缩略图列表,点击跳转

2.3 页面内交互

对于 Mermaid 图表,在笔记页面中提供额外的交互能力:

预览交互

页面交互

鼠标悬停 Mermaid

光标变为 Pointer

右下角显示红色拖拽手柄

拖拽调整图表大小

点击打开预览浮层

全功能工具栏

保持等比缩放

退出 auto-fit 模式

三、技术实现

3.1 整体架构

UI

Preview Layer

Bridge

Capture Layer

DOM 事件

MarkdownPostProcessor

事件委托

收集预览项

打开 Modal

image-capture.ts

笔记 DOM

mermaid-capture.ts

Live Preview

preview-utils.ts

PreviewModal

TransformManager
缩放/旋转/平移状态

NavigationController
项目索引管理

AnnotationCanvas
Canvas 标注叠加层

TouchController
触摸手势

clipboard.ts
复制为 PNG

工具栏
按钮分组

缩略图栏
固定大小导航

内容区
img / SVG 渲染

3.2 模态框生命周期

"DOM" "PreviewModal" "preview-utils" User "DOM" "PreviewModal" "preview-utils" User "onOpen()" "用户交互..." "onClose()" "点击图片/Mermaid" "openUnifiedModal()" "collectAllInSourceOrder()" "new PreviewModal(items, index)" "构建全屏覆盖层" "构建内容区 + 工具栏 + 缩略图栏" "renderCurrent() 渲染当前项" "绑定键盘/鼠标事件" "浮层就绪" "ESC / 点击遮罩 / 关闭按钮" "保存偏好(if enabled)" "清理事件监听" "销毁 Canvas" "清空内容"

3.3 关键实现细节

3.3.1 变换管理(TransformManager)
// 核心状态
class TransformManager {
  scale: number;      // 当前缩放 (0.1 ~ 10.0)
  translateX: number; // 水平偏移
  translateY: number; // 垂直偏移
  rotation: number;   // 旋转角度 (0 / 90 / 180 / 270)
  
  // 应用到 DOM 元素
  applyTo(el: HTMLElement) {
    el.style.transform = `
      translate(${this.translateX}px, ${this.translateY}px)
      scale(${this.scale})
      rotate(${this.rotation}deg)
    `;
  }
}
3.3.2 Mermaid 自适应与拖拽缩放

在页面中通过 MutationObserver 捕获所有 .mermaid 元素,自动添加 width: 100% 适配容器宽度。由于 Mermaid 是异步渲染,bindMermaidElement 内置了 5 次 × 500ms 的重试等待 SVG 元素就绪。右下角的拖拽手柄允许用户手动调整大小:

手动调整

鼠标悬停

显示拖拽手柄

拖拽

移除 auto-fit

固定宽高, 等比缩放

自动适配

Mermaid 渲染

MutationObserver 检测

添加 mine-images-auto-fit

width: 100% !important

3.3.3 缩略图导航

左侧缩略图栏为固定 100×80px 的导航面板,自动收集当前文件所有图片和 Mermaid 图表,点击即可跳转:

// 缩略图构建流程
private buildThumbnailBar(): void {
  this.navigation.items.forEach((item, index) => {
    const thumb = createDiv("mine-images-thumbnail");
    if (item.type === "image") {
      this.loadThumbnailImage(item.source, thumb);
    } else {
      this.renderMermaidThumbnail(item, thumb);
    }
    thumb.addEventListener("click", () => this.navigateTo(index));
  });
}

在这里插入图片描述

3.3.4 标注系统

基于 HTML5 Canvas 实现轻量级标注,支持画笔、箭头、矩形三种模式:

"AnnotationCanvas" "工具栏" User "AnnotationCanvas" "工具栏" User "点击「画笔」/「箭头」/「矩形」" "setMode(mode)" "Canvas pointerEvents = auto" "cursor = crosshair" "mousedown (起点)" "记录 startX, startY" "保存当前 canvas 快照" "mousemove (绘制中)" "还原快照 → 绘制形状" "实时预览" "mouseup (完成)" "最终绘制提交" "点击「清除」" "clear()" "ctx.clearRect()"

在这里插入图片描述

3.4 图片复制流程

同源图片

跨域图片

Mermaid SVG

用户点击复制

图片类型?

fetch → Blob

navigator.clipboard.write

Toast 提示成功

绘制到 Canvas

tainted?

复制 URL 到剪贴板

Toast 提示CORS限制

序列化 SVG

new Image 加载

绘制到 Canvas

转为 PNG Blob

四、未来规划

4.1 路线图

2026-04 2026-05 2026-06 2026-07 2026-08 2026-09 2026-10 "基础 Modal 浮层" "图片/Mermaid 捕获" "缩放/旋转/平移" "复制功能" "设置面板" "全屏模式" "缩略图导航栏" "右键菜单" "偏好记忆" "加载状态优化" "触摸手势" "标注工具" "性能优化" "移动端适配" "Excalidraw 预览" "插件 API 开放" "V1.0 核心预览" "V2.0 增强体验" "V3.0 高级特性" "V4.0 生态扩展" "mineImages 开发路线图"

4.2 短期目标

  • 触摸手势优化:完善双指缩放和旋转体验
  • 标注工具增强:支持颜色选择、笔触粗细、撤销/重做
  • 性能调优:大缩略图列表按需渲染(虚拟滚动),Mermaid 渲染缓存

4.3 长期愿景

  • 移动端支持:适配 Obsidian Mobile,提供触屏友好的交互
  • 更多图表类型:支持 Excalidraw、PlantUML、Graphviz 等
  • 插件生态:开放 API,允许第三方开发者扩展预览类型

项目地址:https://gitee.com/wmlce/mine-images

插件 IDmine-images

许可证:MIT

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐