Files
gh-levnikolaevich-claude-co…/skills/ln-115-presentation-creator/references/mermaid_guidelines.md
2025-11-30 08:37:27 +08:00

390 lines
10 KiB
Markdown

# Mermaid.js Guidelines for x-html-builder
This guide provides best practices for working with Mermaid.js diagrams in HTML presentations with tab-based navigation.
## Version and CDN
**Current Version:** Mermaid v11.12.1 (latest stable as of 2025)
**Recommended CDN:**
```html
<!-- Standard version -->
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<!-- ESM version (modern browsers) -->
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
</script>
```
**Why v11?**
- Latest features and bug fixes
- Improved performance
- Better error handling
- `mermaid.init()` deprecated (use `mermaid.run()` instead)
---
## Initialization for Tab-Based Presentations
**Critical Setting:** `startOnLoad: false`
**Why?**
- Tabs with `display: none` prevent diagrams from rendering correctly
- Diagrams need manual rendering when tab becomes visible
- Allows precise control over rendering timing
**Configuration:**
```javascript
mermaid.initialize({
startOnLoad: false, // Manual control for tab switching
theme: 'default', // or 'dark', 'forest', 'neutral'
securityLevel: 'loose', // For trusted content (allows HTML labels)
logLevel: 1, // 0=none, 1=error, 2=warn, 3=info
flowchart: {
useMaxWidth: true, // Responsive diagrams
htmlLabels: true // Rich text support
}
});
```
---
## Rendering Strategies
### Strategy 1: Render Once Per Tab (Recommended)
**Best for:** Static content with tab navigation
```javascript
document.addEventListener('DOMContentLoaded', async function() {
// Initialize Mermaid
mermaid.initialize({ startOnLoad: false });
// Render initially active tab
const activeTab = document.querySelector('.tab-content.active');
if (activeTab && !activeTab.dataset.mermaidRendered) {
await mermaid.run({
nodes: activeTab.querySelectorAll('.mermaid'),
suppressErrors: true
});
activeTab.dataset.mermaidRendered = 'true'; // Mark as rendered
}
});
async function switchTab(tabName) {
// ... tab switching logic ...
// Render diagrams only if not already rendered
const activeTab = document.getElementById(`${tabName}-tab`);
if (activeTab && !activeTab.dataset.mermaidRendered) {
await mermaid.run({
nodes: activeTab.querySelectorAll('.mermaid'),
suppressErrors: true
});
activeTab.dataset.mermaidRendered = 'true';
}
}
```
**Benefits:**
- ✅ Performance: Each tab rendered only once
- ✅ No duplicate diagrams
- ✅ Minimal re-rendering overhead
### Strategy 2: Render All on Load
**Best for:** Small number of tabs (<5), simple diagrams
```javascript
document.addEventListener('DOMContentLoaded', async function() {
mermaid.initialize({ startOnLoad: false });
// Render ALL diagrams at once
await mermaid.run({
querySelector: '.mermaid',
suppressErrors: true
});
});
```
**Benefits:**
- ✅ Simple implementation
- ✅ No tab-switch delays
- ❌ Slower initial load for many diagrams
### Strategy 3: Manual Rendering API
**Best for:** Dynamic content from API, programmatic diagram generation
```javascript
const graphDefinition = `
graph TD
A[Client] --> B[Load Balancer]
B --> C[Server1]
B --> D[Server2]
`;
const { svg } = await mermaid.render('uniqueId', graphDefinition);
document.getElementById('diagram-container').innerHTML = svg;
```
**Benefits:**
- ✅ Full control over rendering
- ✅ Can modify SVG before insertion
- ✅ Works with dynamic content
---
## Common Errors and Solutions
| Error | Cause | Solution |
|-------|-------|----------|
| **Diagrams not rendering in hidden tabs** | `startOnLoad: true` + `display: none` | Use `startOnLoad: false` + `mermaid.run()` on tab switch |
| **Duplicate diagrams** | Re-rendering already rendered content | Cache rendered tabs with `data-mermaid-rendered` attribute |
| **"mermaid.init is deprecated"** | Using old API | Replace `mermaid.init()` with `mermaid.run()` |
| **SVG sizing issues** | Rendering while element is hidden | Add `setTimeout(... , 50)` before rendering to ensure tab is visible |
| **Parsing errors break page** | Invalid Mermaid syntax | Use `suppressErrors: true` in `mermaid.run()` |
| **Fonts not loaded** | Rendering before fonts ready | Wait for `DOMContentLoaded` + small delay (50-100ms) |
| **Different themes on tabs** | Theme not applied to new renders | Re-initialize theme before rendering: `mermaid.initialize({ theme: 'dark' })` |
---
## Performance Optimization
### 1. Lazy Rendering
Only render diagrams when tab becomes visible (Strategy 1).
### 2. Caching
Use `data-mermaid-rendered` attribute to avoid re-rendering:
```javascript
if (!element.dataset.mermaidRendered) {
await mermaid.run({ nodes: [element] });
element.dataset.mermaidRendered = 'true';
}
```
### 3. Batch Rendering
Render multiple diagrams in one `mermaid.run()` call:
```javascript
// Good: One call for all diagrams in tab
await mermaid.run({ nodes: tab.querySelectorAll('.mermaid') });
// Bad: Multiple calls
diagrams.forEach(d => mermaid.run({ nodes: [d] }));
```
### 4. Error Suppression (Production)
Prevent parsing errors from breaking the page:
```javascript
await mermaid.run({ suppressErrors: true });
```
### 5. Async/Await
Always use async/await for predictable rendering:
```javascript
async function renderDiagrams() {
await mermaid.run({ ... }); // Wait for completion
console.log('Rendering complete');
}
```
---
## Security Levels
**Choose based on content trust level:**
### `loose` (Recommended for Documentation)
```javascript
mermaid.initialize({ securityLevel: 'loose' });
```
- Allows HTML labels
- Allows some scripts in labels
- **Use for:** Internal docs, trusted content
### `strict` (User-Generated Content)
```javascript
mermaid.initialize({ securityLevel: 'strict' });
```
- Blocks all scripts
- Sanitizes HTML
- **Use for:** User-submitted diagrams, public content
### `antiscript` (Middle Ground)
```javascript
mermaid.initialize({ securityLevel: 'antiscript' });
```
- Removes scripts from output
- Allows safe HTML
---
## Code Examples
### Complete Tab-Based Implementation
```javascript
document.addEventListener('DOMContentLoaded', async function() {
// Initialize Mermaid
if (typeof mermaid !== 'undefined') {
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose',
logLevel: 1,
flowchart: {
useMaxWidth: true,
htmlLabels: true
}
});
// Render initially active tab
setTimeout(async () => {
const activeTab = document.querySelector('.tab-content.active');
if (activeTab && !activeTab.dataset.mermaidRendered) {
try {
await mermaid.run({
nodes: activeTab.querySelectorAll('.mermaid'),
suppressErrors: true
});
activeTab.dataset.mermaidRendered = 'true';
} catch (err) {
console.error('Mermaid rendering error:', err);
}
}
}, 100);
}
// Tab switching
async function switchTab(tabName) {
// ... tab activation logic ...
// Render diagrams if not already rendered
if (typeof mermaid !== 'undefined') {
const activeTab = document.getElementById(`${tabName}-tab`);
if (activeTab && !activeTab.dataset.mermaidRendered) {
setTimeout(async () => {
try {
await mermaid.run({
nodes: activeTab.querySelectorAll('.mermaid'),
suppressErrors: true
});
activeTab.dataset.mermaidRendered = 'true';
} catch (err) {
console.error('Mermaid rendering error on tab switch:', err);
}
}, 50);
}
}
}
});
```
### Error Handling with Fallback
```javascript
async function renderMermaidSafe(element) {
try {
await mermaid.run({ nodes: [element] });
} catch (err) {
console.error('Mermaid error:', err);
element.innerHTML = `
<div style="color: red; padding: 10px; border: 1px solid red;">
⚠️ Diagram rendering failed. Check syntax.
</div>
`;
}
}
```
---
## Migration Notes: v10 → v11
**Breaking Changes:**
-`mermaid.init()` is deprecated → Use `mermaid.run()`
- ⚠️ Some theme options renamed (check docs)
**Recommended Changes:**
```javascript
// Old (v10)
mermaid.init(undefined, '.mermaid');
// New (v11)
await mermaid.run({ querySelector: '.mermaid' });
```
**CDN Update:**
```html
<!-- v10 -->
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<!-- v11 -->
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
```
**Compatibility:**
- ✅ All diagram types (flowchart, sequence, class, ER, etc.) work in v11
- ✅ Themes are compatible
- ✅ Configuration options mostly unchanged
---
## Troubleshooting Checklist
When diagrams don't render:
1. **Check CDN loading:**
```javascript
console.log(typeof mermaid); // Should be 'object', not 'undefined'
```
2. **Check initialization:**
```javascript
console.log(mermaid.initialize); // Should be a function
```
3. **Check element visibility:**
```javascript
const el = document.querySelector('.mermaid');
console.log(window.getComputedStyle(el).display); // Should NOT be 'none'
```
4. **Check for syntax errors:**
- Open browser console
- Look for Mermaid parsing errors
- Validate syntax at https://mermaid.live
5. **Check timing:**
- Are you rendering before DOM is ready?
- Is element visible when rendering?
- Try adding `setTimeout(... , 100)` delay
---
## Best Practices Summary
✅ **DO:**
- Use `startOnLoad: false` for tab-based layouts
- Cache rendered tabs with `data-mermaid-rendered`
- Use async/await for predictable rendering
- Add error handling with `suppressErrors: true`
- Wait for element visibility before rendering
- Use `mermaid.run()` (not deprecated `init()`)
❌ **DON'T:**
- Use `startOnLoad: true` with hidden tabs
- Re-render already rendered diagrams
- Render while element has `display: none`
- Use `mermaid.init()` (deprecated)
- Ignore parsing errors in production
- Mix rendering strategies
---
**Version:** 1.0.0
**Last Updated:** 2025-11-06
**Mermaid Version:** v11.12.1
**Compatible with:** x-html-builder v2.3.1+