Skip to content

Instantly share code, notes, and snippets.

@sjgknight
Created August 26, 2024 03:50
Show Gist options
  • Save sjgknight/31851bf2a3cfa96afdbee24e10259d1a to your computer and use it in GitHub Desktop.
Save sjgknight/31851bf2a3cfa96afdbee24e10259d1a to your computer and use it in GitHub Desktop.
Single page tool to take CSVs and map across columns into an LR mermaid flowchart.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="description" content="Tool to take CSVs and map across columns into an LR mermaid flowchart.">
<meta name="author" content="sjgknight with prompting of ChatGPT and customisation">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSV to Mermaid Converter</title>
<!-- Load Mermaid.js -->
<script type="module">
let mermaidImport = undefined
// Import Mermaid if not already imported
mermaidImport ||= await import('https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.7.0/mermaid.esm.min.mjs');
const mermaid = mermaidImport.default;
// Initialize Mermaid
mermaid.initialize({
startOnLoad: false,
securityLevel: 'loose',
maxTextSize: 90000,
flowchart: {
htmlLabels: false,
curve: 'monotoneX',
},
});
window.mermaid = mermaid; // Expose Mermaid to global scope for later use
</script>
</head>
<body>
<h1>CSV to Mermaid Converter</h1>
<input type="file" id="csvFileInput" accept=".csv" />
<h2>Mermaid Output</h2>
<div id="mermaidContainer">
<!-- Mermaid diagram will be rendered inside this container -->
<pre><code id="mermaid" class="mermaid"></code></pre>
</div>
<h2>JSON Data</h2>
<pre id="jsonOutput"></pre> <!-- Element for JSON output -->
<script>
document.getElementById('csvFileInput').addEventListener('change', handleFileSelect);
function handleFileSelect(event) {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = function(e) {
const csvData = e.target.result;
const jsonData = csvToJson(csvData);
// Print JSON data to the page
document.getElementById('jsonOutput').textContent = JSON.stringify(jsonData, null, 2);
const mermaidSyntax = processJson(jsonData);
// Set the Mermaid syntax with proper formatting
//document.getElementById('debug').textContent = mermaidSyntax;
displayMermaidDiagram(mermaidSyntax);
};
reader.readAsText(file);
}
function csvToJson(csvData) {
const rows = csvData.trim().split('\n').map(row => splitCSVRow(row));
const headers = rows[0];
const data = rows.slice(1);
const cellMap = {}; // To store the first occurrence mapping
// Map cell values to names based on their first occurrence
const mappedData = data.map((row, rowIndex) => {
return row.map((cell, colIndex) => {
const cellAddress = `${String.fromCharCode(65 + colIndex)}${rowIndex + 2}`;
const cellValue = cellMap[cell.trim()] || cellAddress; // Use cellAddress as unique node identifier
if (!cellMap[cell.trim()]) {
cellMap[cell.trim()] = cellAddress;
}
return {
value: cellValue, // Unique node identifier
ref: cellAddress,
nodeValue: cell.trim() // Original cell value for display
};
});
});
return { headers, data: mappedData };
}
function processJson(jsonData) {
const { headers, data } = jsonData;
const nodes = [];
const connections = [];
const nodeReferences = {}; // Maps cell values to unique references
// Generate nodes
headers.forEach((header, colIndex) => {
nodes.push(`subgraph ${String.fromCharCode(65 + colIndex)}["\`${sanitizeText(header)}\`"]`);
data.forEach((row) => {
const cell = row[colIndex];
const cellValue = cell.value; // Unique node identifier
const cellRef = cell.ref;
if (cellValue && !nodeReferences[cellValue]) {
nodeReferences[cellValue] = cellRef;
nodes.push(`${cellRef}["\`${cell.nodeValue}\`"]`); // Display original cell value
}
});
nodes.push('end');
});
// Generate connections based on value field
data.forEach((row) => {
let previousCellValue = null;
headers.forEach((header, colIndex) => {
const currentCell = row[colIndex];
const currentCellValue = currentCell.value;
if (previousCellValue) {
connections.push(`${previousCellValue} --> ${currentCellValue}`);
}
previousCellValue = currentCellValue;
});
});
return [...nodes, ...connections].join('\n');
}
function splitCSVRow(row) {
const pattern = /("[^"]*"|[^",\s][^,]*)(?=\s*,|\s*$)/g;
const matches = [];
let match;
while ((match = pattern.exec(row)) !== null) {
matches.push(match[1].replace(/(^"|"$)/g, '')); // Remove surrounding double quotes if present
}
return matches;
}
function sanitizeText(text) {
// Remove any internal double quotes, trim spaces, and ensure valid Mermaid syntax
return text.replace(/"/g, '').trim();
}
function displayMermaidDiagram(mermaidSyntax) {
const mermaidOutput = document.getElementById('mermaid');
// Set the Mermaid syntax with proper formatting
mermaidOutput.textContent = `flowchart TD\n${mermaidSyntax}`;
// Initialize Mermaid to render the diagram
mermaid.init(undefined, document.querySelectorAll('code.mermaid'));
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment