Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save gwpl/4ad330d8a87d72cb65ee2ded981619e5 to your computer and use it in GitHub Desktop.
Save gwpl/4ad330d8a87d72cb65ee2ded981619e5 to your computer and use it in GitHub Desktop.
Mermaid HTML zooming panning template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Full-Screen Mermaid Diagram with Hovering Controls</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
crossorigin="anonymous"
/>
<style>
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
overflow: hidden;
}
/* Full viewport container */
#container {
position: relative;
width: 100vw;
height: 100vh;
background: #f5f5f5;
}
/* Diagram takes full space */
#diagramContainer {
width: 100%;
height: 100%;
overflow: hidden;
cursor: grab;
}
#diagramContainer:active {
cursor: grabbing;
}
#diagramContainer svg {
width: 100%;
height: 100%;
}
/* Floating control panel */
#controls {
position: absolute;
bottom: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.95);
border: 1px solid #ddd;
border-radius: 8px;
padding: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
z-index: 1000;
display: flex;
gap: 4px;
}
#controls button {
width: 36px;
height: 36px;
border: none;
background: white;
cursor: pointer;
border-radius: 6px;
font-size: 16px;
color: #333;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
}
#controls button:hover {
background: #e8e8e8;
transform: scale(1.1);
}
#controls button:active {
transform: scale(0.95);
}
/* Zoom level indicator */
#zoom-level {
position: absolute;
bottom: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 8px 12px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
z-index: 1000;
}
/* Help text */
#help-text {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 12px 16px;
border-radius: 6px;
font-size: 14px;
max-width: 300px;
z-index: 1000;
transition: opacity 0.3s ease;
}
#help-text h3 {
margin: 0 0 8px 0;
font-size: 16px;
}
#help-text p {
margin: 4px 0;
line-height: 1.4;
}
/* Loading indicator */
#loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 20px;
color: #666;
z-index: 999;
}
</style>
</head>
<body>
<div id="container">
<div id="loading">Loading diagram...</div>
<div id="help-text">
<h3>Navigation Controls</h3>
<p>🖱️ <strong>Mouse wheel:</strong> Zoom in/out</p>
<p>🖱️ <strong>Click & drag:</strong> Pan around</p>
<p>⌨️ <strong>Double-click:</strong> Zoom to point</p>
</div>
<div id="zoom-level">Zoom: 100%</div>
<div id="controls">
<button onclick="zoomIn()" title="Zoom In">
<i class="fas fa-search-plus"></i>
</button>
<button onclick="zoomOut()" title="Zoom Out">
<i class="fas fa-search-minus"></i>
</button>
<button onclick="resetZoom()" title="Reset View">
<i class="fas fa-undo"></i>
</button>
<button onclick="fitToScreen()" title="Fit to Screen">
<i class="fas fa-expand"></i>
</button>
</div>
<!-- Mermaid container takes full viewport -->
<div id="diagramContainer" class="mermaid">
graph LR
Start[fa:fa-play Start Process] --> Init[fa:fa-cog Initialize System]
Init --> Config[fa:fa-wrench Load Configuration]
Config --> DB1[fa:fa-database Connect to Database 1]
Config --> DB2[fa:fa-database Connect to Database 2]
Config --> Cache[fa:fa-memory Connect to Redis Cache]
DB1 --> DataLoad1[fa:fa-download Load User Data]
DB2 --> DataLoad2[fa:fa-download Load Product Data]
Cache --> CacheWarm[fa:fa-fire Warm Up Cache]
DataLoad1 --> ProcessUser[fa:fa-users Process User Records]
DataLoad2 --> ProcessProd[fa:fa-box Process Product Records]
CacheWarm --> CacheReady[fa:fa-check Cache Ready]
ProcessUser --> UserValid[fa:fa-check-circle Validate Users]
ProcessProd --> ProdValid[fa:fa-check-circle Validate Products]
UserValid --> Transform1[fa:fa-exchange Transform User Data]
ProdValid --> Transform2[fa:fa-exchange Transform Product Data]
Transform1 --> Aggregate[fa:fa-layer-group Aggregate All Data]
Transform2 --> Aggregate
CacheReady --> Aggregate
Aggregate --> Analysis[fa:fa-chart-line Run Analytics]
Analysis --> Report1[fa:fa-file-alt Generate Sales Report]
Analysis --> Report2[fa:fa-file-alt Generate User Report]
Analysis --> Report3[fa:fa-file-alt Generate Inventory Report]
Report1 --> Format1[fa:fa-paint-brush Format Sales Data]
Report2 --> Format2[fa:fa-paint-brush Format User Data]
Report3 --> Format3[fa:fa-paint-brush Format Inventory Data]
Format1 --> Export1[fa:fa-file-export Export to Excel]
Format2 --> Export2[fa:fa-file-export Export to PDF]
Format3 --> Export3[fa:fa-file-export Export to CSV]
Export1 --> Store[fa:fa-save Store in File System]
Export2 --> Store
Export3 --> Store
Store --> Email[fa:fa-envelope Send Email Notifications]
Store --> Slack[fa:fa-slack Send Slack Notifications]
Store --> Dashboard[fa:fa-tachometer-alt Update Dashboard]
Email --> Complete[fa:fa-flag-checkered Process Complete]
Slack --> Complete
Dashboard --> Complete
Complete --> Cleanup[fa:fa-broom Cleanup Temporary Files]
Cleanup --> Log[fa:fa-history Log Process Results]
Log --> End[fa:fa-stop End Process]
%% Additional branches for error handling
UserValid --> UserError[fa:fa-exclamation-triangle User Validation Error]
ProdValid --> ProdError[fa:fa-exclamation-triangle Product Validation Error]
UserError --> ErrorHandler[fa:fa-tools Error Handler]
ProdError --> ErrorHandler
ErrorHandler --> Retry[fa:fa-redo Retry Process]
Retry --> ProcessUser
Retry --> ProcessProd
%% Monitoring branch
Analysis --> Monitor[fa:fa-desktop System Monitor]
Monitor --> CPU[fa:fa-microchip CPU Usage Check]
Monitor --> Memory[fa:fa-memory Memory Usage Check]
Monitor --> Disk[fa:fa-hdd Disk Usage Check]
CPU --> Alert[fa:fa-bell Alert System]
Memory --> Alert
Disk --> Alert
Alert --> Complete
</div>
</div>
<!-- Load Mermaid ESM module -->
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: false });
</script>
<!-- Load svg-pan-zoom -->
<script src="https://unpkg.com/[email protected]/dist/svg-pan-zoom.min.js"></script>
<!-- Initialize diagram with pan/zoom -->
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
let panZoomInstance;
// Get the DSL content
const dsl = document.querySelector('#diagramContainer').textContent.trim();
// Render the diagram
mermaid.render('zoomableSvg', dsl).then(result => {
// Replace container content with rendered SVG
document.querySelector('#diagramContainer').innerHTML = result.svg;
// Hide loading indicator
document.getElementById('loading').style.display = 'none';
// Initialize svg-pan-zoom
panZoomInstance = svgPanZoom('#zoomableSvg', {
zoomEnabled: true,
controlIconsEnabled: false,
fit: true,
center: true,
minZoom: 0.1,
maxZoom: 10,
zoomScaleSensitivity: 0.3,
dblClickZoomEnabled: true,
mouseWheelZoomEnabled: true,
preventMouseEventsDefault: true,
onZoom: function(newScale) {
updateZoomLevel(newScale);
}
});
// Store instance globally for button access
window.mermaidPanZoom = panZoomInstance;
// Initial zoom level display
updateZoomLevel(panZoomInstance.getZoom());
// Hide help text after 5 seconds
setTimeout(() => {
const helpText = document.getElementById('help-text');
helpText.style.opacity = '0';
setTimeout(() => {
helpText.style.display = 'none';
}, 300);
}, 5000);
}).catch(error => {
console.error('Error rendering diagram:', error);
document.getElementById('loading').textContent = 'Error loading diagram';
});
// Update zoom level display
function updateZoomLevel(scale) {
const percentage = Math.round(scale * 100);
document.getElementById('zoom-level').textContent = `Zoom: ${percentage}%`;
}
// Control functions
window.zoomIn = function() {
if (window.mermaidPanZoom) {
window.mermaidPanZoom.zoomIn();
}
};
window.zoomOut = function() {
if (window.mermaidPanZoom) {
window.mermaidPanZoom.zoomOut();
}
};
window.resetZoom = function() {
if (window.mermaidPanZoom) {
window.mermaidPanZoom.reset();
}
};
window.fitToScreen = function() {
if (window.mermaidPanZoom) {
window.mermaidPanZoom.fit();
window.mermaidPanZoom.center();
}
};
// Keyboard shortcuts
document.addEventListener('keydown', function(e) {
if (!window.mermaidPanZoom) return;
switch(e.key) {
case '+':
case '=':
e.preventDefault();
zoomIn();
break;
case '-':
case '_':
e.preventDefault();
zoomOut();
break;
case '0':
e.preventDefault();
resetZoom();
break;
case 'f':
case 'F':
e.preventDefault();
fitToScreen();
break;
}
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment