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

一、开发背景

1.1 痛点

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

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

1.2 设计目标

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

统一

图片 + Mermaid 同一浮层

流畅

≤500ms 打开

60fps 缩放平移

完整

缩放/旋转/复制/切换

标注/全屏/缩略图导航

一站式预览体验

1.3 技术选型

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

模块选用方案原因
预览容器ModalObsidian 官方推荐,自带遮罩和关闭逻辑
图表捕获(阅读模式)MarkdownPostProcessor原生渲染管道,无需额外渲染
图表捕获(实时预览)DOM 事件委托兼容 .cm-embed-block 中的动态渲染
图片捕获registerDomEvent轻量级,无侵入
变换(缩放/旋转/平移)CSS transformGPU 加速,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 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐