ध्यान दीजिए: यह एआई / एक तरीका है जो अपने परीक्षणों का हिस्सा है. मैं इस पत्रों, मेरी समझ के कागजों, प्रश्नों को खिलाने के लिए मुझे यह लेख तैयार करना पड़ा है. यह मज़ेदार है और मैं कहीं भी नहीं देखा है.
यह पोस्ट पिछले आलेखों पर बनाता है: यदि आप पहले से ही नहीं है, जाँच करें मेक्स के साथ .jks जोड़ रहे हैं, मेरशी के लिए प्रसंग स्विच किया जा रहा है, और मेरलिंग मेकर डायग्राम को पैन/ZE तथा निर्यात के साथ निर्यात. यह गहरी तेज़ी से उन कार्यान्वयनों के पीछे के भीतरी हिस्से को समझाता है.
मर्बोर्ग वास्तव में शानदार है. सरल पाठ लिखें, सुंदर आरेख प्राप्त करें. कोई अधिक fioooooo के साथ ठोकर, स्रोत फ़ाइलों को खोने, या अलग छवि फ़ाइलों को बनाए रखने के लिए. सब कुछ अपने कोड के साथ, संस्करण पर नियंत्रण.
लेकिन मैं जानना चाहता था कैसे यह वास्तव में सिरों के नीचे काम करता है. यह कैसे करता है:
graph LR
A[Text] --> B[Magic?]
B --> C[Beautiful Diagram]
... एक वास्तविक एसवीजी बन सकते हैं? और अधिक महत्वपूर्ण बात है, आप इसमें ऐसे विशेषताओं को जोड़ने के लिए हुक कैसे कर सकते हैं जैसे कैंच/ टाइटम, प्रसंग स्विच, और निर्यात जो मैं इस साइट के लिए बनाया है (अब उपलब्ध है) @ action: button)?
मेरशी के स्रोत कोड के माध्यम से खुदाई करने के बाद और असली विस्तार बनाने के बारे में, यहाँ सब कुछ मैंने सीखा है कि कैसे Merka आंतरिक काम करता है और कैसे इसे ठीक से आगे बढ़ने के लिए।
मर्करी अपने पाठ परिभाषा आरेखों में बदल जाती है. सोचो " आरेखों के लिए जारी करें."
पुराना तरीका:
मेरशी का रास्ता:
इसे अद्यतन करें? पाठ को संपादित करें. संस्करण नियंत्रण? यह सिर्फ पाठ है! चिह्न में कार्य करता है? हाँ!
मेरिकर डायग्राम क़िस्मों की एक अजीब संख्या का समर्थन करती है:
graph LR
A[Flowcharts] --> B[Sequence Diagrams]
B --> C[Class Diagrams]
C --> D[State Diagrams]
D --> E[ER Diagrams]
E --> F[Gantt Charts]
F --> G[Pie Charts]
G --> H[Git Graphs]
H --> I[User Journeys]
I --> J[And many more...]
देखें मेरशी डॉ. पूरी सूची के लिए.
यहाँ क्या होता है जब मर्कर एक आरेख का अनुवाद करता है:
graph TD
A[Text Definition] --> B[Lexer/Tokenizer]
B --> C[Parser]
C --> D[AST Built]
D --> E[Diagram Type Detected]
E --> F[Type-Specific Renderer]
F --> G[SVG Generated]
G --> H[Inserted into DOM]
H --> I[Your Enhancements Run]
style A stroke:#059669,stroke-width:3px,color:#10b981
style D stroke:#2563eb,stroke-width:3px,color:#3b82f6
style G stroke:#7c3aed,stroke-width:3px,color:#8b5cf6
style I stroke:#d97706,stroke-width:3px,color:#f59e0b
चलो हर कदम तोड़ देते हैं.
सब कुछ पाठ से शुरू होता है. आप मेकर के DSL में डायग्राम लिखते हैं (डो विशेष भाषा):
// Flowchart
const diagram = `
graph TD
A[Start] --> B{Is it working?}
B -->|Yes| C[Great!]
B -->|No| D[Debug time]
`;
Lexexer पाठ को संकेतों में भंग करता है. उदाहरण के लिए, इस पंक्ति के लिए:
A[Start] --> B{Decision}
निशानियाँ ऐसे हैं:
[
{ type: 'NODE_ID', value: 'A' },
{ type: 'NODE_TEXT', value: 'Start' },
{ type: 'ARROW', value: '-->' },
{ type: 'NODE_ID', value: 'B' },
{ type: 'NODE_TEXT', value: 'Decision' },
{ type: 'NODE_SHAPE', value: 'diamond' } // from { }
]
साइन लैंग्वेज में जलती हुई निशानों को काटती है और सजावट के पेड़ को मज़बूत करती है।
// Simplified AST structure
{
type: 'flowchart',
direction: 'TD',
nodes: [
{ id: 'A', text: 'Start', shape: 'rect' },
{ id: 'B', text: 'Decision', shape: 'diamond' }
],
edges: [
{ from: 'A', to: 'B', type: 'arrow' }
]
}
मेरिकर हर आरेख क़िस्म के लिए अलग - अलग वर्ग प्रयोग करती है । जेनन (जैसे Yacc /बाइसन)
मरकक डायग्राम क़िस्म प्रथम पंक्ति से पता चलता है:
// Simplified detection logic
if (text.match(/^\s*graph/)) return 'flowchart';
if (text.match(/^\s*sequenceDiagram/)) return 'sequence';
if (text.match(/^\s*classDiagram/)) return 'class';
// ... etc
प्रत्येक आरेख क़िस्म का अपना ही रेंडरर है. रेंडरकर्ता अट्स लेता है और एसवीजी तत्वों को बनाता है.
Dakts के लिए, मेरक का उपयोग करता है डैम्पर ग्राफ ख़ाका के लिए लाइब्रेरी. अन्यों के लिए, यह मनपसंद एल्गोरिदम या लायब्रेरीज़ जैसे पुस्तकालय उपयोग करता है.
// Simplified flowchart renderer
export const draw = function (text, id, version, diagObj) {
const graph = diagObj.db; // The AST
const svg = d3.select(`#${id}`);
// Render nodes
graph.getVertices().forEach(vertex => {
drawNode(svg, vertex);
});
// Render edges
graph.getEdges().forEach(edge => {
drawEdge(svg, edge);
});
// Apply layout algorithm
dagre.layout(graph);
};
रेंडर करनेवाला एसवीजी मार्कअप उत्पन्न करता है:
<svg xmlns="http://www.w3.org/2000/svg">
<g class="node">
<rect x="0" y="0" width="100" height="50"/>
<text x="50" y="25">Start</text>
</g>
<g class="edge">
<path d="M 100 25 L 200 25" stroke="#333"/>
</g>
</svg>
मेरशी सब कुछ पाती है .mermaid दिए गए एसवीजी में से तत्वों तथा बदल कर बदलें:
// From mermaid.ts
export const init = async function (config, nodes) {
const nodesToProcess = nodes || document.querySelectorAll('.mermaid');
for (const node of nodesToProcess) {
const id = `mermaid-${Date.now()}-${Math.random()}`;
const txt = node.textContent;
const { svg } = await render(id, txt);
node.innerHTML = svg;
}
};
मेरपिक एसवीजी प्रविष्ट करने के बाद, आप इसे बढ़ा सकते हैं. यह है जहां मेरे सभी सहायक हुक में हुक है:
नीचे इस पर अधिक.
अब कि हम जानते हैं कि कैसे मेरशी काम करती है, चलो यह विस्तार करने के लिए खोजने की कोशिश करें।
सबसे अधिक मूल एक्सटेंशन कॉन्फ़िगरेशन है:
import mermaid from 'mermaid';
mermaid.initialize({
startOnLoad: true,
theme: 'dark',
securityLevel: 'loose',
flowchart: {
curve: 'basis',
padding: 15
}
});
मैं इस व्यापक में कवर मेरशी के लिए प्रसंग स्विच किया जा रहा है, लेकिन यहाँ है कुंजी कार्यान्वयन:
मैरिकर को एक प्रसंग के साथ प्रारंभ करने की जरूरत है, और आप इसे बदल नहीं सकते. B. B. हालांकि यदि आप एक नए प्रसंग के साथ फिर से देना चाहते हैं, आप मूल डायग्राम स्रोत की जरूरत है - जो मेरशीक है. डॉम में स्टोर नहीं है.
छवि फ़ाइल नाम प्रदर्शित करने से पहले मूल सामग्री संग्रह भंडारित करें, तब फिर बहाल करें व फिर से अभ्यास करें जब प्रसंग स्विच हो जाए:
// From my theme-switcher implementation
const originalData = new Map();
// Save original content before first render
const saveOriginalData = async () => {
const elements = document.querySelectorAll('.mermaid');
elements.forEach(element => {
const id = element.id || `mermaid-${Date.now()}`;
element.id = id;
// Store the original diagram source
if (!originalData.has(id)) {
originalData.set(id, element.textContent?.trim());
}
});
};
// When theme changes, restore and re-render
const loadMermaid = async (theme) => {
mermaid.initialize({
startOnLoad: false,
theme: theme
});
const elements = document.querySelectorAll('.mermaid');
for (const element of elements) {
const source = originalData.get(element.id);
if (source) {
element.innerHTML = ''; // Clear
element.removeAttribute('data-processed');
const { svg } = await mermaid.render(
`mermaid-svg-${element.id}`,
source
);
element.innerHTML = svg;
}
}
};
बहु प्रसंग जांच विधियाँ (मीटर प्रसंग अलग तरह से संभालता है):
function detectTheme() {
// Check various sources
if (typeof window.__themeState !== 'undefined') {
return window.__themeState;
}
if (localStorage.theme) {
return localStorage.theme;
}
if (document.documentElement.classList.contains('dark')) {
return 'dark';
}
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark';
}
return 'light';
}
देखें संपूर्ण प्रसंग स्विचर कोड विवरण के लिए.
यह वह जगह है जहाँ वास्तविक जादू होता है ।
मैं इस व्यापक में कवर मेरलिंग मेकर डायग्राम को पैन/ZE तथा निर्यात के साथ निर्यात, तो मैं यहाँ मुख्य तकनीकों को विशिष्ट करेंगे.
नियंत्रण के लिए रैपर कंटेनर बनाएँ:
function wrapDiagram(element) {
if (element.closest('.mermaid-wrapper')) {
return element.closest('.mermaid-wrapper');
}
const wrapper = document.createElement('div');
wrapper.className = 'mermaid-wrapper';
wrapper.id = `wrapper-${element.id}`;
element.parentNode.insertBefore(wrapper, element);
wrapper.appendChild(element);
return wrapper;
}
उपयोग में ओलम्पेन-जो:
import svgPanZoom from 'svg-pan-zoom';
const panZoomInstances = new Map();
function initPanZoom(svgElement, diagramId) {
// Clean up existing instance
if (panZoomInstances.has(diagramId)) {
panZoomInstances.get(diagramId).destroy();
panZoomInstances.delete(diagramId);
}
const instance = svgPanZoom(svgElement, {
zoomEnabled: true,
controlIconsEnabled: false,
fit: true,
center: true,
minZoom: 0.1,
maxZoom: 10
});
panZoomInstances.set(diagramId, instance);
return instance;
}
फ्लोटिंग नियंत्रक फलक बनाएँ:
function createControlButtons(container, diagramId) {
const controlsDiv = document.createElement('div');
controlsDiv.className = 'mermaid-controls';
const buttons = [
{ icon: 'bx-fullscreen', title: 'Fullscreen', action: 'fullscreen' },
{ icon: 'bx-zoom-in', title: 'Zoom In', action: 'zoomIn' },
{ icon: 'bx-zoom-out', title: 'Zoom Out', action: 'zoomOut' },
{ icon: 'bx-reset', title: 'Reset', action: 'reset' },
{ icon: 'bx-move', title: 'Pan', action: 'pan' },
{ icon: 'bx-image', title: 'Export PNG', action: 'exportPng' },
{ icon: 'bx-code-alt', title: 'Export SVG', action: 'exportSvg' }
];
buttons.forEach(btn => {
const button = document.createElement('button');
button.className = `mermaid-control-btn bx ${btn.icon}`;
button.setAttribute('data-action', btn.action);
button.setAttribute('data-diagram-id', diagramId);
controlsDiv.appendChild(button);
});
container.appendChild(controlsDiv);
}
प्रत्येक बटन पर श्रोताओं को संलग्न नहीं करें. एक-दूसरे को उपयोग करें:
document.addEventListener('click', (e) => {
const target = e.target;
if (!target.classList.contains('mermaid-control-btn')) return;
const action = target.getAttribute('data-action');
const diagramId = target.getAttribute('data-diagram-id');
const panZoom = panZoomInstances.get(diagramId);
switch (action) {
case 'zoomIn': panZoom?.zoomIn(); break;
case 'zoomOut': panZoom?.zoomOut(); break;
case 'reset': panZoom?.reset(); break;
// ... etc
}
});
चुनौती: एसवीजी तत्वों में गतिशीलता है, टाइट/ टाइटम बदलना, और विरासत में स्वरूपित शैलियाँ हैं. सही तरह से निर्यात करने के लिए, आप की आवश्यकता है:
उपयोग में एचटीएमएल- टू-image:
import { toPng, toSvg } from 'html-to-image';
async function exportDiagram(container, format, diagramId) {
const svgElement = container.querySelector('svg');
if (!svgElement) return;
// Clone to avoid modifying original
const clonedSvg = svgElement.cloneNode(true);
// Get or calculate viewBox
let viewBox = clonedSvg.getAttribute('viewBox');
if (!viewBox) {
const bbox = svgElement.getBBox();
viewBox = `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`;
clonedSvg.setAttribute('viewBox', viewBox);
}
// Set explicit dimensions
const [, , width, height] = viewBox.split(' ').map(Number);
clonedSvg.setAttribute('width', width);
clonedSvg.setAttribute('height', height);
// Remove pan-zoom transforms
clonedSvg.removeAttribute('style');
// Create off-screen container
const temp = document.createElement('div');
temp.style.position = 'absolute';
temp.style.left = '-9999px';
temp.appendChild(clonedSvg);
document.body.appendChild(temp);
// Export
const dataUrl = format === 'png'
? await toPng(clonedSvg, { pixelRatio: 2 })
: await toSvg(clonedSvg);
downloadFile(dataUrl, `diagram-${Date.now()}.${format}`);
// Cleanup
document.body.removeChild(temp);
}
गंभीर विवरण:
देखें पूरा निर्यात कोड अधिक विवरण के लिए.
मैं इन सभी सुधारों को इस रूप में पैकेज किया @ action: button. देखें प्रकाशन मेकरीक को एनएमपी पैकेज के रूप में सलाह दी जाती है पूरी जानकारी के लिए।
यहाँ यह सब एक साथ फिट कैसे है:
graph TB
A[User Initializes] --> B[init Function]
B --> C[initMermaid]
B --> D[enhanceMermaidDiagrams]
C --> E[Theme Detection]
C --> F[Event Listeners]
C --> G[Mermaid Rendering]
E --> E1[Global State]
E --> E2[LocalStorage]
E --> E3[DOM Class]
E --> E4[OS Preference]
F --> F1[Custom Events]
F --> F2[Media Query]
G --> H[Apply Enhancements]
D --> H
H --> I[Wrap Diagrams]
H --> J[Init Pan/Zoom]
H --> K[Add Controls]
I --> L[Interactive Diagram]
J --> L
K --> L
L --> M[User Interactions]
M --> M1[Zoom In/Out]
M --> M2[Pan]
M --> M3[Fullscreen]
M --> M4[Export PNG/SVG]
style A stroke:#059669,stroke-width:3px,color:#10b981
style L stroke:#2563eb,stroke-width:3px,color:#3b82f6
style M stroke:#7c3aed,stroke-width:3px,color:#8b5cf6
npm install @mostlylucid/mermaid-enhancements
import { init } from '@mostlylucid/mermaid-enhancements';
import '@mostlylucid/mermaid-enhancements/styles.css';
await init();
यह है! आपकी मर्क जंगली आरेखों अब है:
मैं में कवर के रूप में मेक्स के साथ .jks जोड़ रहे हैं, आप HMMMMMX सामग्री के बाद मेकर मरिपित को फिर से स्थापित करने की जरूरत है:
// On page load
document.addEventListener('DOMContentLoaded', function () {
mermaid.initialize({ startOnLoad: true });
});
// After HTMX swaps content
document.body.addEventListener('htmx:afterSwap', function(evt) {
mermaid.run();
});
सुधार पैकेज के साथ:
import { init, enhanceMermaidDiagrams } from '@mostlylucid/mermaid-enhancements';
// Initial load
await init();
// After HTMX swap
document.body.addEventListener('htmx:afterSwap', async function() {
await init(); // Re-init Mermaid with current theme
enhanceMermaidDiagrams(); // Re-apply enhancements
});
इस सामान और डिबगिंग किनारे के मामलों को बनाने के बाद, यहाँ क्या काम करता है:
मेरशी मूल आरेख स्रोत को रेंडरिंग के बाद संरक्षित नहीं करती है. आप इसे अपने आप को जमा करते हैं:
const originalData = new Map();
// Before first render
element.setAttribute('data-original-code', element.textContent);
originalData.set(element.id, element.textContent);
// When re-rendering
element.innerHTML = originalData.get(element.id);
नए लोगों को बनाने से पहले स्मृति रिसाव वास्तविक है.
if (panZoomInstances.has(id)) {
try {
panZoomInstances.get(id).destroy();
} catch (e) {
console.warn('Failed to destroy:', e);
}
panZoomInstances.delete(id);
}
प्रत्येक बटनों को श्रोताओं को संलग्न नहीं करें:
// ❌ Don't do this
buttons.forEach(btn => {
btn.addEventListener('click', handler);
});
// ✅ Do this
document.addEventListener('click', (e) => {
if (e.target.matches('.mermaid-control-btn')) {
handleClick(e.target);
}
});
रॉकनेट लोडर जावास्क्रिप्ट चलाने में देरी करता है. निर्भरता के लिए इंतजार करें:
function waitForDependencies(maxAttempts = 50) {
return new Promise((resolve) => {
let attempts = 0;
const check = () => {
if (window.mermaid && window.htmx && window.Alpine) {
resolve();
} else if (attempts >= maxAttempts) {
resolve(); // Give up
} else {
attempts++;
setTimeout(check, Math.min(50 * Math.pow(1.2, attempts), 500));
}
};
check();
});
}
और अपने मुख्य स्क्रिप्ट को रॉकेट से अलग करें:
<script src="main.js" data-cfasync="false"></script>
प्रयोक्ता requestAnimationFrame मनमानी से बेहतर समय के लिए setTimeout:
// After Mermaid renders
await mermaid.run();
// Wait for paint before enhancing
await new Promise(resolve => {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
enhanceMermaidDiagrams();
resolve();
});
});
});
एसवीजी अजीब हो सकता है. हमेशा चेक करें:
const svgElement = container.querySelector('svg');
if (!svgElement) {
console.warn('No SVG found');
return;
}
// Clone before modifying
const cloned = svgElement.cloneNode(true);
// Ensure viewBox exists
let viewBox = cloned.getAttribute('viewBox');
if (!viewBox) {
const bbox = svgElement.getBBox();
viewBox = `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`;
}
सही आरंभ के साथ, आपको देखना चाहिए:
Saving original data
Loading mermaid with theme: dark
Mermaid initialized
Enhanced 3 diagrams
सुधारों को लागू करने के बाद:
आरेख अनुवाद नहीं:
window.mermaid)पैन/जोम काम नहीं कर रहा है:
pointer-events: none)सिर्फ कोने कैप्चर्स निर्यात करें:
प्रसंग स्विच नहीं कर रहा है:
data-processed रीसेट नहींजब तक आवश्यक हो, सुधारों को लोड नहीं करें:
let enhancementsLoaded = false;
async function loadEnhancements() {
if (enhancementsLoaded) return;
const { enhanceMermaidDiagrams } = await import('./enhancements.js');
enhanceMermaidDiagrams();
enhancementsLoaded = true;
}
// Load on first interaction
document.addEventListener('click', (e) => {
if (e.target.closest('.mermaid')) {
loadEnhancements();
}
}, { once: true });
सिर्फ जब दिखाई दे रहा हो तो आरेखों को रेंडर करें:
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
renderDiagram(entry.target);
observer.unobserve(entry.target);
}
});
}, { rootMargin: '100px' });
document.querySelectorAll('.mermaid').forEach(el => {
observer.observe(el);
});
नया प्रसंग परिवर्तन करने पर:
let timeout;
window.addEventListener('resize', () => {
clearTimeout(timeout);
timeout = setTimeout(() => {
panZoomInstances.forEach(instance => {
instance.resize();
instance.fit();
});
}, 250);
});
मेरशीश बॉक्स से शानदार है, लेकिन समझ में आता है कि यह कैसे आंतरिक रूप से काम करता है आप कुछ वास्तव में ठंडा पैदा करने देता है। मुख्य अंतर्दृष्टि:
requestAnimationFrameसभी तकनीकों मैं यहाँ कवर किया है इस साइट पर उत्पादन में उपयोग किया जाता है और विकास में @ action: buttonपूर्ण स्रोत उपलब्ध है अधिकतर अल्पपारदर्शिता/ सबसे ज्यादा जर्दी.
ऊपर आरेख पर नियंत्रण की कोशिश करो!
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.