Skip to main content
Introducing DiagView
  1. Blog/

Introducing DiagView

Khadirullah Mohammad
Author
Khadirullah Mohammad
Former IT fixer turned DevOps Engineer. I build CI/CD pipelines, manage AWS infrastructure, and automate incident workflows — with Docker, Kubernetes, Terraform, and Python.
Table of Contents

As developers, we love clear documentation. Use Case diagrams, Cloud Architectures, Flowcharts — they are the lifeblood of understanding complex systems. Tools like Mermaid.js, PlantUML, and Draw.io are fantastic for creating them.

But viewing them? That experience is often stuck in the past.

If you export a complex architecture diagram as an SVG and embed it on your docs site, it’s just a static image. The text is too small to read, you can’t search for that one specific microservice, and if you zoom with your browser, the whole page breaks.

I looked for a library to solve this. I found D3.js (too complex for just viewing) and Leaflet (too heavy for a diagram). I didn’t want to write hundreds of lines of code just to let a user zoom into a flowchart.

So, I built DiagView.

Demo
#

Zoom, pan, search, minimap, and export in action

What is DiagView?
#

DiagView is a feature-rich, interactive wrapper that gives your static SVGs superpowers.

It is built on top of the excellent panzoom library, which handles the low-level matrix math for smooth 60fps zooming and panning. But while panzoom gives you the engine, DiagView gives you the entire car.

Feature Overview
#

FeatureDescription
🔍 Deep SearchTraverses the SVG DOM to find and highlight matching nodes with pulsing glow
📤 Multi-Format ExportPNG, SVG, PDF, JPEG, WebP, or copy to clipboard
🗺️ Smart MinimapAccurate portrait/landscape scaling; click-to-navigate
🔄 Rotation90° rotation steps with correct Panzoom recalibration
📝 Text Select ModeToggle SVG text selection for copying node labels (press T)
🎯 Meeting ModeBuilt-in laser pointer for remote presentations
🔗 Precision Share LinksGenerate URLs that preserve exact zoom/pan position
⌨️ Keyboard NavigationFull keyboard control — zoom, pan, search, rotate, share
🌗 Auto-ThemingDetects Tailwind, Bootstrap, and system dark/light mode
📱 Mobile-First TouchPinch-to-zoom, double-tap to reset, Visual Viewport sync
🔒 SVG SanitizationThree-tier security model (strict/permissive/off)
🎭 3 Layout ModesHeader toolbar, floating FAB, or invisible click-to-open
🔧 Per-Diagram OverridesSet layout, accent, scale per diagram via data-* attributes
🌐 Shadow DOM SupportWorks inside Shadow DOM roots
🔄 Remember ZoomPersist zoom/pan state per diagram across modal opens
🏷️ WatermarksCustomizable watermarks on export (corner, background, four-sides)
📦 4 Button StylesTransparent, accent, solid, neutral — match any UI

The Landscape: Why Wasn’t This Already Solved?
#

Before writing any code, I scoured npm and GitHub. Here’s what I found:

D3.js — The titan of data visualization. But D3 is for creating graphics from data, not for viewing pre-made SVGs.

svg-pan-zoom — A focused library for adding pan/zoom to SVGs. But it’s just the engine — no UI, no search, no export.

Leaflet.js — The standard for interactive maps. Overkill for a simple flowchart.

The gap was clear: I needed a batteries-included solution — something that would just work with a single init() call.

Quick Start
#

CDN (Fastest)
#

<!-- Panzoom (required for zoom/pan) -->
<script src="https://cdn.jsdelivr.net/npm/@panzoom/[email protected]/dist/panzoom.min.js"></script>

<!-- DiagView -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/diagview.umd.min.js"></script>

<!-- Your diagram -->
<div class="diagram">
  <svg><!-- Your SVG content --></svg>
</div>

<!-- Initialize -->
<script>
  DiagView.init();
</script>

NPM
#

npm install diagview @panzoom/panzoom
import DiagView from 'diagview';

DiagView.init({
  layout: 'floating',
  accentColor: '#3b82f6',
});

Flexible Layouts
#

DiagView supports three layout modes to fit your design:

Layout Options
Header, Floating, and Off layout modes
LayoutBest For
HeaderClassic top-bar controls, documentation sites
FloatingClean HUD-style buttons on hover, minimal UIs
OffInvisible UI, the diagram itself is the trigger

Header Layout
#

A full-width toolbar is always visible above the diagram. Best for documentation sites and dashboards where discoverability matters.

Header Layout
Header layout — toolbar always visible

Floating Layout
#

A circular FAB button appears at the bottom-right. Controls hover in at the bottom of the diagram card. Clean and minimal.

Floating Layout
Floating layout — minimal FAB button

Off Layout
#

No controls are rendered. The diagram itself is the trigger — clicking it opens the fullscreen viewer.

Off Layout
Off layout — click anywhere on the diagram to open

Per-Diagram Overrides
#

Any diagram can override the global configuration using data-diagview-* attributes. This lets you mix layout modes and accent colors on a single page:

<!-- Purple accent with header layout for this diagram only -->
<div class="diagram"
  data-diagview-layout="header"
  data-diagview-accent="#8b5cf6"
  data-diagview-scale="6"
  data-title="My Architecture">
  <svg>...</svg>
</div>

<!-- This diagram uses the global defaults -->
<div class="diagram">
  <svg>...</svg>
</div>
AttributeValuesDescription
data-diagview-layoutheader | floating | offLayout for this diagram only
data-diagview-accentAny CSS colorAccent color for this diagram only
data-diagview-scale110Export resolution for this diagram only
data-diagview-sanitizestrict | permissive | offSVG sanitization mode
data-diagview-allow-remotetrue | falseAllow remote CSS/fonts in SVG
data-diagview-watermarktrue | falseEnable watermark for this diagram
data-diagview-watermark-textAny stringCustom watermark text
data-titleAny stringTitle shown in header layout

Keyboard Shortcuts
#

All shortcuts are active when the fullscreen modal is open:

KeyAction
EscClose fullscreen
Space / 0Reset zoom — fit to screen
+ / =Zoom in
- / _Zoom out
↑ ↓ ← →Pan diagram
Shift + arrowsFast pan (3× speed)
FFocus search input
TToggle text-select mode
RRotate 90° clockwise
MToggle meeting mode (laser pointer)
LCopy share link to clipboard
?Show/hide keyboard shortcuts panel

Under the Hood: Technical Decisions
#

The Search Engine
#

This was the feature I was most proud of. The search system:

  1. Pre-Caches Candidates — On first open, queries all text elements and stores them in a WeakMap
  2. Uses Dirty Checking — Before writing to the DOM, checks if values have changed
  3. Batches Updates — All DOM mutations are wrapped in requestAnimationFrame

The result? Searching through diagrams with 2,500+ nodes is instant.

Fullscreen View
#

Clicking any diagram opens it in a fullscreen modal with all controls — zoom, pan, search, export, rotate, share, and minimap:

Fullscreen View
Fullscreen modal with all controls

Text Select Mode
#

Press T in fullscreen and all SVG text nodes become selectable. You can highlight and copy node labels, edge text, or any text content inside the diagram. Press T again to disable. This is useful when you need to copy a specific service name or ID from a complex architecture diagram.

Minimap
#

When a diagram is zoomed in so that parts of it are outside the viewport, a minimap automatically appears in the corner. It shows your current viewport position within the full diagram, and you can click anywhere on the minimap to jump to that area. The minimap correctly handles both portrait and landscape diagrams.

Minimap View
Smart minimap with click-to-navigate

Rotation
#

Press R to rotate the diagram 90° clockwise. This is particularly useful for tall diagrams (like vertical flowcharts) that would be easier to read horizontally. The rotation recalibrates the Panzoom instance so zoom and pan continue to work correctly after rotation.

SVG Sanitization
#

DiagView includes a three-tier security model for SVG content:

ModeWhat It BlocksWhen to Use
strict (default)<script>, <iframe>, <foreignObject>, <animate>, inline event handlers, <style> injectionUntrusted SVGs (user-uploaded, third-party)
permissive<script>, <iframe>, <object> onlySemi-trusted SVGs (your own diagrams with animations)
offNothingFully trusted SVGs only

Watermarks
#

Watermarks are applied only during export/download — they never appear in the interactive viewer. You can configure them globally or per-diagram:

DiagView.init({
  watermark: {
    enabled: true,
    text: "Confidential",
    style: "corner",        // "corner" | "background" | "both"
    position: "bottom-right", // 6 positions + "four-sides"
    opacity: 0.2,
  },
});

The Export System
#

The export module handles edge cases:

  • Robust Dimension Calculation — Uses getBBox() to find actual content area
  • Cross-Origin Font Handling — Inlines Google Fonts for consistent exports
  • High-DPI Scaling — Up to 10x resolution for print-quality images
  • Transparent Background — PNG and WebP support transparent backgrounds
  • PDF Export — Lazy-loads jsPDF from CDN only when needed

Export Formats
#

FormatTransparentNotes
PNGHigh-res raster; default 4× scale
SVGFully scalable vector
JPEGSmallest file size
WebPModern format; good compression
PDFRequires jsPDF (lazy-loaded from CDN)
CopyCopies PNG to system clipboard

Optional Panzoom Dependency
#

I made panzoom an optional peer dependency:

  • With panzoom: Full zoom, pan, touch gestures
  • Without panzoom: Fullscreen, search, and export still work

This keeps DiagView usable even in constrained environments.

Mobile Support
#

DiagView is fully optimized for mobile — pinch-to-zoom, double-tap to reset, and Visual Viewport sync for stability on iOS and Android:

Mobile View
Mobile-optimized touch interface

Button Styles
#

Four built-in styles for the diagram card buttons:

StyleLook
accent (default)Colored with your accent color
transparentTransparent with subtle hover
solidSolid background
neutralMuted, blends into the background
DiagView.init({
  ui: {
    buttons: { style: "transparent" }
  }
});

CI/CD Pipeline
#

One thing I invested heavily in was the automation pipeline. Every push to the repository triggers a GitHub Actions workflow that:

  1. Lints the code with ESLint
  2. Runs 169 unit tests with Jest
  3. Builds the UMD and ESM bundles with Rollup
  4. Publishes to npm on tagged releases (semantic versioning)
  5. Deploys documentation to GitHub Pages
# Simplified GitHub Actions workflow
on:
  push:
    tags: ['v*']  # Triggers on version tags like v1.0.6

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run lint
      - run: npm test          # 169 tests
      - run: npm run build

  publish:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - run: npm publish       # Pushes to npm registry

The pipeline ensures that no broken code gets published. If any test fails, the publish step never runs. This is the same pattern used in production CI/CD — just applied to an open-source package.

The project also uses:

  • Husky — pre-commit hooks that run lint-staged
  • lint-staged — runs ESLint + Prettier only on changed files
  • release-it — automated version bumping, changelog generation, and npm publishing
  • size-limit — CI fails if bundle size exceeds the budget (34 KB UMD, 38 KB ESM)

Bundle Size
#

MetricSize
UMD Minified~34 KB
ESM Minified~38 KB
Gzipped (Transfer)~19 KB

For context, that’s smaller than a single hero image. And it includes all CSS, SVG icons, and the entire UI framework.

Framework Support
#

DiagView is framework-agnostic — it works with plain HTML, React, Vue, Svelte, Angular, or any framework that renders SVGs to the DOM. It also supports Shadow DOM and Mermaid.js integration.

Full Configuration
#

DiagView.init({
  // Layout
  layout: 'floating',           // 'header' | 'floating' | 'off'

  // Theme (null = auto-detect)
  accentColor: null,
  backgroundColor: null,
  textColor: null,

  // UI
  ui: { buttons: { style: 'accent' } },
  showKeyboardHelp: true,
  showBranding: true,
  showMinimap: true,
  animateOpen: true,

  // Interaction
  naturalPanning: false,
  immersiveMode: false,
  rememberZoom: false,
  printFriendly: true,

  // Zoom limits
  maxZoomScale: 25,
  minZoomScale: 0.05,

  // Export
  highResScale: 4,               // 1–10
  mobileScale: 2,                // 1–5
  maxPixels: 16777216,           // 16MP safety cap

  // Security
  security: {
    mode: 'strict',
    allowOverrides: true,
    allowRemoteResources: false,
  },

  // Watermarks (export only)
  watermark: {
    enabled: false,
    text: '',
    style: 'corner',
    position: 'bottom-right',
    opacity: 0.2,
  },

  // Callbacks
  onExport: null,
  onError: null,
  onZoomChange: null,
  onOpen: null,
  onClose: null,
});

Try It Out
#

I built this to scratch my own itch. If you write technical documentation for a living, I think you’ll find it useful too.

Have feedback or found a bug? Open an issue on GitHub.