Flowcharts are essential tools for visualizing processes, making complex tasks easier to understand and execute. They serve as a bridge between ideas and actions, providing clarity and direction.
In this article, we will explore ten diverse flowchart examples that can streamline your workflow and enhance productivity. Each example is designed to address specific needs, from project management to software development.
CODE1
Here's the code:
CODETEXT1
CODE2
Here's the code:
CODETEXT2
CODE3
Here's the code:
CODETEXT3
CODE4
Here's the code:
CODETEXT4
CODE5
Here's the code:
CODETEXT5
Designers and developers love Subframe for its drag-and-drop interface and intuitive, responsive canvas. Create pixel-perfect UI effortlessly, ensuring every detail is just right.
Experience the ease and precision that Subframe offers. Start for free today!
CODE6
Here's the code:
CODETEXT6
CODE7
Here's the code:
CODETEXT7
CODE8
Here's the code:
CODETEXT8
CODE9
Here's the code:
CODETEXT9
CODE10
Here's the code:
CODETEXT10
Unlock the power of Subframe to design stunning UIs and flowcharts with unmatched efficiency. Create pixel-perfect designs effortlessly, ensuring every detail is just right.
Experience the ease and precision that Subframe offers. Start for free and begin creating immediately!
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Enterprise Workflow Flowchart</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f5f5f5; display: flex; justify-content: center; align-items: center; min-height: 700px; overflow: hidden; } .flowchart-container { width: 680px; height: 660px; background-color: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); padding: 20px; position: relative; overflow: hidden; } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px; padding-bottom: 15px; border-bottom: 1px solid #eaeaea; } .title { font-size: 20px; font-weight: 600; color: #333; } .controls { display: flex; gap: 10px; } .control-btn { background-color: #f5f5f5; border: none; border-radius: 4px; padding: 6px 12px; font-size: 12px; cursor: pointer; transition: all 0.2s ease; color: #555; } .control-btn:hover { background-color: #e9e9e9; } .control-btn.active { background-color: #555; color: white; } .workflow-canvas { width: 100%; height: calc(100% - 70px); position: relative; overflow: hidden; } .node { position: absolute; width: 180px; background-color: white; border-radius: 6px; padding: 12px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08); cursor: move; user-select: none; transition: all 0.2s ease, transform 0.1s ease; z-index: 1; } .node::before { content: ''; position: absolute; left: 0; top: 0; height: 100%; width: 4px; border-radius: 6px 0 0 6px; } .node:hover { box-shadow: 0 4px 15px rgba(0, 0, 0, 0.12); transform: translateY(-2px); } .node.active { box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); z-index: 10; } .node-type-initiation::before { background-color: #3498db; } .node-type-approval::before { background-color: #e74c3c; } .node-type-processing::before { background-color: #2ecc71; } .node-type-decision::before { background-color: #f39c12; } .node-type-completion::before { background-color: #9b59b6; } .node-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } .node-title { font-size: 14px; font-weight: 600; color: #333; } .node-badge { font-size: 10px; padding: 2px 6px; border-radius: 10px; font-weight: 500; } .node-badge-initiation { background-color: rgba(52, 152, 219, 0.1); color: #3498db; } .node-badge-approval { background-color: rgba(231, 76, 60, 0.1); color: #e74c3c; } .node-badge-processing { background-color: rgba(46, 204, 113, 0.1); color: #2ecc71; } .node-badge-decision { background-color: rgba(243, 156, 18, 0.1); color: #f39c12; } .node-badge-completion { background-color: rgba(155, 89, 182, 0.1); color: #9b59b6; } .node-content { font-size: 12px; color: #666; line-height: 1.4; } .node-metrics { display: flex; justify-content: space-between; margin-top: 10px; padding-top: 8px; border-top: 1px solid #f0f0f0; font-size: 11px; color: #888; } .detail-panel { position: absolute; bottom: -220px; left: 0; right: 0; height: 220px; background-color: #fff; box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.08); padding: 20px; transition: bottom 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); z-index: 20; border-top: 1px solid #eee; overflow-y: auto; } .detail-panel.active { bottom: 0; } .detail-header { display: flex; justify-content: space-between; margin-bottom: 15px; } .detail-title { font-size: 16px; font-weight: 600; color: #333; } .detail-close { background: none; border: none; color: #888; cursor: pointer; font-size: 18px; } .detail-content { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; } .detail-section { margin-bottom: 15px; } .detail-label { font-size: 12px; color: #888; margin-bottom: 4px; } .detail-value { font-size: 13px; color: #333; } .detail-stakeholders { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; } .stakeholder { background-color: #f5f5f5; border-radius: 12px; padding: 4px 10px; font-size: 11px; color: #555; } .connector { position: absolute; background-color: #ddd; z-index: 0; pointer-events: none; transition: background-color 0.2s ease; } .connector.highlighted { background-color: #888; } .connector-arrow { position: absolute; width: 0; height: 0; border-style: solid; transition: border-color 0.2s ease; z-index: 0; pointer-events: none; } .connector-arrow.highlighted .connector-arrow-head { border-color: transparent transparent transparent #888; } .connector-arrow-head { position: absolute; width: 0; height: 0; border-style: solid; border-width: 6px 0 6px 8px; border-color: transparent transparent transparent #ddd; } .instructions { position: absolute; top: 20px; left: 50%; transform: translateX(-50%); background-color: rgba(255, 255, 255, 0.9); padding: 10px 15px; border-radius: 4px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); font-size: 12px; color: #555; z-index: 100; pointer-events: none; opacity: 0; transition: opacity 0.3s ease; } .instructions.show { opacity: 1; } .loading-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(255, 255, 255, 0.8); display: flex; flex-direction: column; justify-content: center; align-items: center; z-index: 1000; } .loading-spinner { width: 40px; height: 40px; border: 3px solid #f3f3f3; border-top: 3px solid #555; border-radius: 50%; animation: spin 1s linear infinite; margin-bottom: 10px; } .loading-text { font-size: 14px; color: #555; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @media (max-width: 700px) { .flowchart-container { width: 100%; height: 100%; border-radius: 0; padding: 15px; } .node { width: 160px; padding: 10px; } .detail-content { grid-template-columns: 1fr; } } </style> </head> <body> <div class="flowchart-container"> <div class="header"> <div class="title">Procurement Approval Process</div> <div class="controls"> <button class="control-btn" id="zoom-out">-</button> <button class="control-btn" id="zoom-reset">Reset</button> <button class="control-btn" id="zoom-in">+</button> <button class="control-btn" id="help-btn">?</button> </div> </div> <div class="workflow-canvas" id="canvas"> <!-- Nodes will be dynamically created --> </div> <div class="detail-panel" id="detailPanel"> <div class="detail-header"> <div class="detail-title" id="detailTitle">Node Details</div> <button class="detail-close" id="detailClose">×</button> </div> <div class="detail-content" id="detailContent"> <!-- Details will be dynamically populated --> </div> </div> <div class="instructions" id="instructions"> Click and drag nodes to rearrange. Click a node to view details. </div> <div class="loading-overlay" id="loadingOverlay"> <div class="loading-spinner"></div> <div class="loading-text">Loading workflow...</div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const canvas = document.getElementById('canvas'); const detailPanel = document.getElementById('detailPanel'); const detailTitle = document.getElementById('detailTitle'); const detailContent = document.getElementById('detailContent'); const detailClose = document.getElementById('detailClose'); const instructions = document.getElementById('instructions'); const loadingOverlay = document.getElementById('loadingOverlay'); const helpBtn = document.getElementById('help-btn'); const zoomInBtn = document.getElementById('zoom-in'); const zoomOutBtn = document.getElementById('zoom-out'); const zoomResetBtn = document.getElementById('zoom-reset'); let activeNode = null; let isDragging = false; let initialX, initialY; let currentZoom = 1; let nodes = []; let connections = []; // Node data const nodeData = [ { id: 'n1', title: 'Request Initiation', type: 'initiation', content: 'Department submits purchase requisition with specifications and cost estimates.', x: 60, y: 50, metrics: { time: '1-2 days', approval: 'Auto' }, details: { owner: 'Department Manager', startDate: 'Day 1', inputs: 'Requisition form, Cost justification', outputs: 'Validated requisition', stakeholders: ['Department Head', 'Finance Analyst', 'Requester'], description: 'This phase initiates the procurement process, where departments fill out standardized requisition forms with detailed specifications, justification, and preliminary budget estimates. System auto-validates for completeness.' } }, { id: 'n2', title: 'Budget Verification', type: 'processing', content: 'Finance team validates the requisition against departmental budget allocations.', x: 60, y: 180, metrics: { time: '1-3 days', approval: 'Finance' }, details: { owner: 'Finance Department', startDate: 'Day 3', inputs: 'Validated requisition, Budget data', outputs: 'Budget-approved requisition', stakeholders: ['Senior Finance Manager', 'Budget Analyst', 'Department Manager'], description: 'Finance reviews the request against the department's quarterly and annual budget allocations. Confirms if funds are available and properly allocated to the cost center. May request reallocation or additional funding approval if necessary.' } }, { id: 'n3', title: 'Value Assessment', type: 'decision', content: 'Route based on purchase value: standard or enhanced approval process.', x: 60, y: 310, metrics: { time: 'Same day', approval: 'Auto' }, details: { owner: 'Procurement System', startDate: 'Day 6', inputs: 'Budget-approved requisition', outputs: 'Categorized request', stakeholders: ['Procurement Officer'], description: 'Automatic decision point that routes the request based on monetary thresholds. Purchases under $10,000 follow standard approval, while those above require enhanced scrutiny including competitive bidding and additional approvals.' } }, { id: 'n4', title: 'Standard Approval', type: 'approval', content: 'Department head approval for requests under $10,000.', x: 300, y: 220, metrics: { time: '1-2 days', approval: 'Dept. Head' }, details: { owner: 'Department Director', startDate: 'Day 7', inputs: 'Categorized request (standard)', outputs: 'Approved purchase order', stakeholders: ['Department Director', 'Procurement Officer'], description: 'Streamlined approval for routine and lower-value purchases. Department director reviews and approves based on business need and budget availability. Requires only single-level approval to proceed to vendor selection.' } }, { id: 'n5', title: 'Enhanced Approval', type: 'approval', content: 'Multi-tier approval required for high-value purchases.', x: 300, y: 380, metrics: { time: '3-7 days', approval: 'Multi-level' }, details: { owner: 'VP of Operations', startDate: 'Day 7', inputs: 'Categorized request (enhanced)', outputs: 'Executive-approved requisition', stakeholders: ['Department Director', 'VP Finance', 'COO', 'Procurement Director'], description: 'Rigorous approval process for high-value purchases requiring multiple levels of sign-off. Includes review of strategic alignment, TCO analysis, and potential alternatives. May require board approval for purchases exceeding $100,000.' } }, { id: 'n6', title: 'Vendor Selection', type: 'processing', content: 'Procurement team selects vendor based on approved criteria.', x: 440, y: 310, metrics: { time: '2-10 days', approval: 'Procurement' }, details: { owner: 'Procurement Team', startDate: 'Day 14', inputs: 'Approved requisition', outputs: 'Vendor selection, Draft contract', stakeholders: ['Procurement Specialist', 'Vendor Manager', 'Legal Advisor'], description: 'Selection of appropriate vendor following company procurement policy. Standard purchases utilize preferred vendors list, while enhanced processes require competitive bidding, vendor presentations, and formal evaluation matrices.' } }, { id: 'n7', title: 'Legal Review', type: 'approval', content: 'Legal department reviews contract terms for compliance.', x: 440, y: 170, metrics: { time: '2-5 days', approval: 'Legal' }, details: { owner: 'Legal Department', startDate: 'Day 24', inputs: 'Draft contract, Vendor documentation', outputs: 'Legally approved contract', stakeholders: ['Corporate Counsel', 'Compliance Officer', 'Procurement Manager'], description: 'Legal review ensures contractual terms protect company interests and mitigate risks. Examines liability provisions, termination clauses, IP rights, compliance requirements, and payment terms. May negotiate specific terms with vendor legal representatives.' } }, { id: 'n8', title: 'Purchase Execution', type: 'completion', content: 'Contract signing, PO generation, and order placement.', x: 440, y: 50, metrics: { time: '1-2 days', approval: 'Final' }, details: { owner: 'Procurement Officer', startDate: 'Day 29', inputs: 'Approved contract, Final requisition', outputs: 'Executed contract, Purchase order', stakeholders: ['CFO', 'Procurement Director', 'Department Requester'], description: 'Final execution phase where appropriate signatories execute the contract, the system generates formal purchase orders, and procurement communicates with the vendor to initiate delivery. Includes establishing milestone tracking in the procurement management system.' } } ]; // Connection data const connectionData = [ { from: 'n1', to: 'n2' }, { from: 'n2', to: 'n3' }, { from: 'n3', to: 'n4' }, { from: 'n3', to: 'n5' }, { from: 'n4', to: 'n6' }, { from: 'n5', to: 'n6' }, { from: 'n6', to: 'n7' }, { from: 'n7', to: 'n8' } ]; // Simulate loading delay setTimeout(() => { loadingOverlay.style.display = 'none'; // Create nodes nodeData.forEach(data => { createNode(data); }); // Create connections connectionData.forEach(conn => { createConnection(conn.from, conn.to); }); // Show instructions briefly instructions.classList.add('show'); setTimeout(() => { instructions.classList.remove('show'); }, 3000); drawConnections(); }, 1500); function createNode(data) { const node = document.createElement('div'); node.className = `node node-type-${data.type}`; node.id = data.id; node.dataset.type = data.type; node.style.left = `${data.x}px`; node.style.top = `${data.y}px`; node.innerHTML = ` <div class="node-header"> <div class="node-title">${data.title}</div> <div class="node-badge node-badge-${data.type}">${capitalizeFirstLetter(data.type)}</div> </div> <div class="node-content">${data.content}</div> <div class="node-metrics"> <span>⏱️ ${data.metrics.time}</span> <span>✓ ${data.metrics.approval}</span> </div> `; node.addEventListener('mousedown', handleNodeMouseDown); node.addEventListener('click', (e) => { if (!isDragging) { showNodeDetails(data); } }); canvas.appendChild(node); nodes.push({ element: node, data: data }); } function createConnection(fromId, toId) { connections.push({ from: fromId, to: toId }); } function drawConnections() { // Remove existing connectors document.querySelectorAll('.connector, .connector-arrow').forEach(el => el.remove()); connections.forEach(conn => { const fromNode = document.getElementById(conn.from); const toNode = document.getElementById(conn.to); if (fromNode && toNode) { const fromRect = fromNode.getBoundingClientRect(); const toRect = toNode.getBoundingClientRect(); const canvasRect = canvas.getBoundingClientRect(); const fromX = (fromRect.left + fromRect.right) / 2 - canvasRect.left; const fromY = (fromRect.top + fromRect.bottom) / 2 - canvasRect.top; const toX = (toRect.left + toRect.right) / 2 - canvasRect.left; const toY = (toRect.top + toRect.bottom) / 2 - canvasRect.top; // Determine exit and entry points based on relative positions let startX, startY, endX, endY; if (Math.abs(fromX - toX) > Math.abs(fromY - toY)) { // Horizontal connection if (fromX < toX) { startX = fromRect.right - canvasRect.left; startY = fromY; endX = toRect.left - canvasRect.left; endY = toY; } else { startX = fromRect.left - canvasRect.left; startY = fromY; endX = toRect.right - canvasRect.left; endY = toY; } } else { // Vertical connection if (fromY < toY) { startX = fromX; startY = fromRect.bottom - canvasRect.top; endX = toX; endY = toRect.top - canvasRect.top; } else { startX = fromX; startY = fromRect.top - canvasRect.top; endX = toX; endY = toRect.bottom - canvasRect.top; } } drawLine(startX, startY, endX, endY, fromNode.id === activeNode?.id || toNode.id === activeNode?.id); } }); } function drawLine(x1, y1, x2, y2, isHighlighted) { const length = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2); const angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI; const connector = document.createElement('div'); connector.className = `connector ${isHighlighted ? 'highlighted' : ''}`; connector.style.width = `${length - 10}px`; connector.style.height = '2px'; connector.style.left = `${x1}px`; connector.style.top = `${y1}px`; connector.style.transform = `rotate(${angle}deg)`; connector.style.transformOrigin = 'left center'; const arrow = document.createElement('div'); arrow.className = `connector-arrow ${isHighlighted ? 'highlighted' : ''}`; arrow.style.left = `${x2 - 12}px`; arrow.style.top = `${y2 - 6}px`; const arrowHead = document.createElement('div'); arrowHead.className = 'connector-arrow-head'; arrowHead.style.transform = `rotate(${angle}deg)`; arrowHead.style.transformOrigin = 'center'; arrow.appendChild(arrowHead); canvas.appendChild(connector); canvas.appendChild(arrow); } function handleNodeMouseDown(e) { const node = e.currentTarget; isDragging = false; initialX = e.clientX; initialY = e.clientY; // Set active class document.querySelectorAll('.node').forEach(n => n.classList.remove('active')); node.classList.add('active'); activeNode = nodes.find(n => n.element === node); // Highlight connections drawConnections(); // Add movement handlers document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); e.preventDefault(); } function handleMouseMove(e) { if (Math.abs(e.clientX - initialX) > 5 || Math.abs(e.clientY - initialY) > 5) { isDragging = true; const node = document.querySelector('.node.active'); if (node) { const nodeData = nodes.find(n => n.element === node).data; const dx = e.clientX - initialX; const dy = e.clientY - initialY; nodeData.x += dx; nodeData.y += dy; node.style.left = `${nodeData.x}px`; node.style.top = `${nodeData.y}px`; drawConnections(); initialX = e.clientX; initialY = e.clientY; } } } function handleMouseUp() { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); // If it was just a click (not a drag), keep the node active if (!isDragging) { // The click handler will take care of showing details } else { isDragging = false; } } function showNodeDetails(nodeData) { detailTitle.textContent = nodeData.title; const details = nodeData.details; detailContent.innerHTML = ` <div class="detail-section"> <div class="detail-label">Process Owner</div> <div class="detail-value">${details.owner}</div> </div> <div class="detail-section"> <div class="detail-label">Typical Start</div> <div class="detail-value">${details.startDate}</div> </div> <div class="detail-section"> <div class="detail-label">Inputs</div> <div class="detail-value">${details.inputs}</div> </div> <div class="detail-section"> <div class="detail-label">Outputs</div> <div class="detail-value">${details.outputs}</div> </div> <div class="detail-section" style="grid-column: span 2;"> <div class="detail-label">Key Stakeholders</div> <div class="detail-stakeholders"> ${details.stakeholders.map(s => `<div class="stakeholder">${s}</div>`).join('')} </div> </div> <div class="detail-section" style="grid-column: span 2;"> <div class="detail-label">Process Description</div> <div class="detail-value">${details.description}</div> </div> `; detailPanel.classList.add('active'); } // Helper function to capitalize first letter function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } // Event listeners detailClose.addEventListener('click', () => { detailPanel.classList.remove('active'); }); helpBtn.addEventListener('click', () => { instructions.classList.toggle('show'); setTimeout(() => { instructions.classList.remove('show'); }, 3000); }); // Zoom controls zoomInBtn.addEventListener('click', () => { if (currentZoom < 1.5) { currentZoom += 0.1; applyZoom(); } }); zoomOutBtn.addEventListener('click', () => { if (currentZoom > 0.6) { currentZoom -= 0.1; applyZoom(); } }); zoomResetBtn.addEventListener('click', () => { currentZoom = 1; applyZoom(); }); function applyZoom() { canvas.style.transform = `scale(${currentZoom})`; canvas.style.transformOrigin = 'center center'; setTimeout(() => { drawConnections(); }, 100); } // Window resize handler window.addEventListener('resize', () => { drawConnections(); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Educational Process Flowchart</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f9f7f7; display: flex; justify-content: center; align-items: center; min-height: 700px; overflow-x: hidden; padding: 20px; } .container { width: 100%; max-width: 700px; height: 100%; max-height: 700px; overflow-y: auto; background-color: white; border-radius: 24px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); padding: 25px; position: relative; } .header { text-align: center; margin-bottom: 30px; position: relative; } h1 { color: #6a4c93; font-size: 2rem; margin-bottom: 10px; position: relative; display: inline-block; } h1::after { content: ''; position: absolute; bottom: -10px; left: 50%; transform: translateX(-50%); width: 80%; height: 4px; background: linear-gradient(90deg, #f9c74f, #f94144, #90be6d); border-radius: 4px; } .subtitle { color: #666; font-size: 0.9rem; max-width: 500px; margin: 0 auto; margin-top: 20px; } .flowchart { display: flex; flex-direction: column; align-items: center; gap: 40px; padding: 20px 0; position: relative; } .step { width: 85%; padding: 25px 30px; border-radius: 18px; position: relative; transition: all 0.3s ease; cursor: pointer; display: flex; flex-direction: column; align-items: center; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); z-index: 2; } .step:hover { transform: translateY(-5px); box-shadow: 0 15px 25px rgba(0, 0, 0, 0.1); } .step-1 { background-color: #fde4cf; border: 2px solid #f9c74f; } .step-2 { background-color: #ceead6; border: 2px solid #90be6d; } .step-3 { background-color: #d0e8fd; border: 2px solid #577590; } .step-4 { background-color: #f5d5e3; border: 2px solid #c77dff; } .step-5 { background-color: #d9ecf2; border: 2px solid #43aa8b; } .step-number { position: absolute; top: -15px; left: -15px; background-color: white; width: 40px; height: 40px; border-radius: 50%; display: flex; justify-content: center; align-items: center; font-weight: bold; color: #6a4c93; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border: 3px solid; transition: all 0.3s ease; } .step-1 .step-number { border-color: #f9c74f; } .step-2 .step-number { border-color: #90be6d; } .step-3 .step-number { border-color: #577590; } .step-4 .step-number { border-color: #c77dff; } .step-5 .step-number { border-color: #43aa8b; } .step-title { font-weight: 600; font-size: 1.2rem; margin-bottom: 10px; color: #333; display: flex; align-items: center; gap: 10px; } .step-content { font-size: 0.9rem; color: #555; text-align: center; max-width: 500px; } .icon { width: 30px; height: 30px; display: flex; justify-content: center; align-items: center; } .connections { position: absolute; top: 0; left: 50%; height: 100%; width: 6px; background-color: #e1e1e1; transform: translateX(-50%); z-index: 1; } .tooltip { position: absolute; bottom: -10px; right: -10px; background-color: #6a4c93; color: white; border-radius: 50%; width: 24px; height: 24px; display: flex; justify-content: center; align-items: center; cursor: pointer; font-size: 0.8rem; transition: all 0.3s ease; } .tooltip:hover { transform: scale(1.1); } .tooltip-content { position: absolute; bottom: calc(100% + 10px); right: 0; background-color: white; padding: 15px; border-radius: 10px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); width: 250px; opacity: 0; visibility: hidden; transition: all 0.3s ease; font-size: 0.85rem; color: #333; z-index: 10; } .tooltip:hover .tooltip-content { opacity: 1; visibility: visible; } .branch { position: relative; width: 100%; display: flex; justify-content: center; gap: 20px; } .decision-point { width: 80px; height: 80px; background-color: #f8edeb; border: 2px solid #f4a261; border-radius: 50%; display: flex; justify-content: center; align-items: center; font-weight: bold; color: #6a4c93; position: relative; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); z-index: 2; margin-top: 20px; } .decision-point:hover { transform: scale(1.05); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); } .branch-options { display: flex; justify-content: space-around; width: 90%; margin-top: 20px; } .branch-option { padding: 15px 20px; border-radius: 12px; background-color: #f0f0f0; text-align: center; font-size: 0.85rem; color: #555; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05); width: 45%; position: relative; } .branch-option.option-a { background-color: #e6f7ff; border: 2px solid #90cdf4; } .branch-option.option-b { background-color: #fff0f6; border: 2px solid #f8a5c2; } .branch-option:hover { transform: translateY(-3px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); } .branch-option .tooltip { right: -5px; bottom: -5px; width: 20px; height: 20px; font-size: 0.7rem; } .floating-elements { position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; overflow: hidden; z-index: 0; } .floating-element { position: absolute; opacity: 0.2; animation: float 15s linear infinite; } .pencil { top: 15%; left: 10%; animation-delay: 0s; animation-duration: 20s; } .book { top: 60%; right: 8%; animation-delay: 2s; animation-duration: 25s; } .lightbulb { top: 35%; right: 15%; animation-delay: 5s; animation-duration: 18s; } .note { bottom: 20%; left: 15%; animation-delay: 7s; animation-duration: 22s; } @keyframes float { 0% { transform: translateY(0) rotate(0deg); } 25% { transform: translateY(-15px) rotate(5deg); } 50% { transform: translateY(0) rotate(0deg); } 75% { transform: translateY(15px) rotate(-5deg); } 100% { transform: translateY(0) rotate(0deg); } } .progress-indicator { position: fixed; top: 20px; right: 20px; display: flex; flex-direction: column; gap: 8px; z-index: 100; } .progress-dot { width: 12px; height: 12px; border-radius: 50%; background-color: #e1e1e1; transition: all 0.3s ease; cursor: pointer; } .progress-dot.active { background-color: #6a4c93; transform: scale(1.2); } @media (max-width: 600px) { .container { padding: 15px; } h1 { font-size: 1.6rem; } .subtitle { font-size: 0.8rem; } .step { width: 95%; padding: 20px; } .step-title { font-size: 1rem; } .step-content { font-size: 0.8rem; } .branch-options { flex-direction: column; align-items: center; gap: 20px; } .branch-option { width: 90%; } } .tooltip-arrow { position: absolute; bottom: -10px; right: 10px; width: 0; height: 0; border-left: 10px solid transparent; border-right: 10px solid transparent; border-top: 10px solid white; } .completion-badge { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); background-color: #6a4c93; color: white; padding: 10px 20px; border-radius: 30px; font-size: 0.9rem; opacity: 0; transition: all 0.5s ease; display: flex; align-items: center; gap: 10px; cursor: pointer; } .completion-badge.visible { opacity: 1; animation: pulse 2s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(106, 76, 147, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(106, 76, 147, 0); } 100% { box-shadow: 0 0 0 0 rgba(106, 76, 147, 0); } } /* Custom scrollbar */ .container::-webkit-scrollbar { width: 8px; } .container::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 4px; } .container::-webkit-scrollbar-thumb { background: #6a4c93; border-radius: 4px; } .container::-webkit-scrollbar-thumb:hover { background: #5a3c83; } </style> </head> <body> <div class="container"> <div class="header"> <h1>Learning Journey Map</h1> <p class="subtitle">Navigate through the educational process from initial curiosity to mastery with this interactive flowchart.</p> </div> <div class="flowchart"> <div class="connections"></div> <div class="step step-1" data-step="1"> <div class="step-number">1</div> <div class="step-title"> <div class="icon">📚</div> <span>Exploration & Curiosity</span> </div> <p class="step-content">Begin with questions and initial engagement. This phase is about sparking interest and identifying learning goals.</p> <div class="tooltip">? <div class="tooltip-content"> Try connecting subjects to students' lived experiences and interests to promote meaningful engagement. <div class="tooltip-arrow"></div> </div> </div> </div> <div class="step step-2" data-step="2"> <div class="step-number">2</div> <div class="step-title"> <div class="icon">💡</div> <span>Foundational Knowledge</span> </div> <p class="step-content">Build fundamental concepts and vocabulary. Focus on creating a strong conceptual framework for advanced learning.</p> <div class="tooltip">? <div class="tooltip-content"> Visual learning aids and concept maps significantly improve retention of foundational principles. <div class="tooltip-arrow"></div> </div> </div> </div> <div class="step step-3" data-step="3"> <div class="step-number">3</div> <div class="step-title"> <div class="icon">🔍</div> <span>Critical Analysis</span> </div> <p class="step-content">Develop analytical thinking and problem-solving skills. Question assumptions and evaluate different perspectives.</p> <div class="tooltip">? <div class="tooltip-content"> Socratic questioning techniques promote deeper critical thinking and help students identify logical inconsistencies. <div class="tooltip-arrow"></div> </div> </div> </div> <div class="branch" data-step="4"> <div class="decision-point"> <div class="icon">⚡</div> </div> </div> <div class="branch-options"> <div class="branch-option option-a"> <strong>Applied Practice</strong> <p>Hands-on application through projects, labs, and real-world problem solving</p> <div class="tooltip">? <div class="tooltip-content"> Project-based learning increases knowledge retention by up to 60% compared to lecture-only formats. <div class="tooltip-arrow"></div> </div> </div> </div> <div class="branch-option option-b"> <strong>Theoretical Deepening</strong> <p>Advanced concept exploration, research, and complex theoretical frameworks</p> <div class="tooltip">? <div class="tooltip-content"> Theoretical work develops metacognition and creates versatile mental models applicable across domains. <div class="tooltip-arrow"></div> </div> </div> </div> </div> <div class="step step-4" data-step="5"> <div class="step-number">4</div> <div class="step-title"> <div class="icon">🔄</div> <span>Integration & Synthesis</span> </div> <p class="step-content">Connect different knowledge domains and create meaningful relationships between concepts. Develop a holistic understanding.</p> <div class="tooltip">? <div class="tooltip-content"> Cross-disciplinary projects help students see connections between seemingly unrelated subjects, strengthening overall comprehension. <div class="tooltip-arrow"></div> </div> </div> </div> <div class="step step-5" data-step="6"> <div class="step-number">5</div> <div class="step-title"> <div class="icon">🌟</div> <span>Mastery & Teaching</span> </div> <p class="step-content">Demonstrate expertise through creation, innovation, and ability to teach others. The ultimate test of understanding.</p> <div class="tooltip">? <div class="tooltip-content"> The "Learning Pyramid" model suggests that teaching others has a 90% retention rate, the highest of all learning methods. <div class="tooltip-arrow"></div> </div> </div> </div> </div> <div class="floating-elements"> <div class="floating-element pencil">✏️</div> <div class="floating-element book">📖</div> <div class="floating-element lightbulb">💡</div> <div class="floating-element note">📝</div> </div> <div class="progress-indicator"> <div class="progress-dot active" data-step="1"></div> <div class="progress-dot" data-step="2"></div> <div class="progress-dot" data-step="3"></div> <div class="progress-dot" data-step="4"></div> <div class="progress-dot" data-step="5"></div> <div class="progress-dot" data-step="6"></div> </div> <div class="completion-badge"> <span>🎓</span> <span>Journey completed! Click to restart</span> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const steps = document.querySelectorAll('.step, .branch'); const progressDots = document.querySelectorAll('.progress-dot'); const completionBadge = document.querySelector('.completion-badge'); let currentStep = 1; let totalSteps = steps.length + 1; // +1 for the final step after the branch options // Initialize updateVisibility(); // Handle step clicks steps.forEach(step => { step.addEventListener('click', function() { if (parseInt(this.dataset.step) === currentStep) { currentStep++; updateVisibility(); } }); }); // Handle branch option clicks document.querySelectorAll('.branch-option').forEach(option => { option.addEventListener('click', function() { if (currentStep === 5) { // The step after the decision point currentStep++; updateVisibility(); } }); }); // Handle progress dot clicks progressDots.forEach(dot => { dot.addEventListener('click', function() { currentStep = parseInt(this.dataset.step); updateVisibility(); }); }); // Handle completion badge click completionBadge.addEventListener('click', function() { currentStep = 1; updateVisibility(); completionBadge.classList.remove('visible'); // Scroll to top document.querySelector('.container').scrollTo({ top: 0, behavior: 'smooth' }); }); function updateVisibility() { // Update steps visibility steps.forEach(step => { const stepNum = parseInt(step.dataset.step); if (stepNum < currentStep) { step.style.opacity = "1"; step.style.pointerEvents = "none"; } else if (stepNum === currentStep) { step.style.opacity = "1"; step.style.pointerEvents = "auto"; step.classList.add('pulse'); // Scroll to the current step step.scrollIntoView({ behavior: 'smooth', block: 'center' }); setTimeout(() => { step.classList.remove('pulse'); }, 1000); } else { step.style.opacity = "0.5"; step.style.pointerEvents = "none"; } }); // Update branch options visibility if (currentStep === 5) { document.querySelectorAll('.branch-option').forEach(option => { option.style.opacity = "1"; option.style.pointerEvents = "auto"; }); } else if (currentStep > 5) { document.querySelectorAll('.branch-option').forEach(option => { option.style.opacity = "1"; option.style.pointerEvents = "none"; }); } else { document.querySelectorAll('.branch-option').forEach(option => { option.style.opacity = "0.5"; option.style.pointerEvents = "none"; }); } // Update progress dots progressDots.forEach(dot => { const dotStep = parseInt(dot.dataset.step); if (dotStep <= currentStep) { dot.classList.add('active'); } else { dot.classList.remove('active'); } }); // Show completion badge when all steps are completed if (currentStep > totalSteps) { completionBadge.classList.add('visible'); } else { completionBadge.classList.remove('visible'); } } // Add hover effects document.querySelectorAll('.step, .branch-option, .decision-point').forEach(element => { element.addEventListener('mouseenter', function() { if (this.style.pointerEvents !== 'none') { this.style.transform = this.classList.contains('decision-point') ? 'scale(1.05)' : 'translateY(-5px)'; } }); element.addEventListener('mouseleave', function() { if (this.style.pointerEvents !== 'none') { this.style.transform = 'none'; } }); }); // Add pulse animation to the first step initially if (steps.length > 0) { steps[0].classList.add('pulse'); setTimeout(() => { steps[0].classList.remove('pulse'); }, 1000); } }); </script> </body> </html>
<html> <head> <title>Healthcare Decision Flowchart</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Roboto', 'Helvetica Neue', sans-serif; } body { background-color: #f8f9fa; color: #2d3436; overflow-x: hidden; max-width: 700px; margin: 0 auto; height: 700px; padding: 16px; position: relative; } .container { width: 100%; height: 100%; position: relative; overflow-y: auto; padding-bottom: 20px; } h1 { color: #2d3436; font-size: 1.6rem; font-weight: 500; text-align: center; margin: 10px 0 15px; position: relative; padding-bottom: 8px; } h1::after { content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 80px; height: 3px; background: linear-gradient(90deg, #ff6b6b, #ff9e7d); } .flowchart { position: relative; padding: 10px; background-color: white; border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05); margin-bottom: 20px; transition: all 0.3s ease; max-height: 600px; overflow-y: auto; } .node { border-radius: 8px; background-color: white; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08); margin: 20px auto; max-width: 400px; position: relative; transition: all 0.3s ease; overflow: hidden; transform: translateY(20px); opacity: 0; animation: fadeIn 0.5s forwards; } @keyframes fadeIn { to { transform: translateY(0); opacity: 1; } } .node-content { padding: 16px; position: relative; } .node-header { display: flex; align-items: center; margin-bottom: 10px; } .node-icon { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: 50%; margin-right: 12px; color: white; } .icon-assessment { background-color: #4b7bec; } .icon-treatment { background-color: #26de81; } .icon-decision { background-color: #fd9644; } .icon-critical { background-color: #fc5c65; } .node-title { font-weight: 500; font-size: 1.1rem; margin: 0; color: #2d3436; } .node-description { color: #636e72; font-size: 0.9rem; line-height: 1.4; margin-bottom: 12px; } .node-actions { display: flex; flex-wrap: wrap; gap: 8px; } .action-btn { background-color: #f1f2f6; color: #2d3436; border: none; border-radius: 6px; padding: 8px 16px; font-size: 0.85rem; cursor: pointer; transition: all 0.2s ease; font-weight: 500; display: flex; align-items: center; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); } .action-btn:hover, .action-btn:focus { background-color: #e9ecef; transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } .action-btn.primary { background-color: #4b7bec; color: white; } .action-btn.primary:hover, .action-btn.primary:focus { background-color: #3867d6; } .action-btn.critical { background-color: #fc5c65; color: white; } .action-btn.critical:hover, .action-btn.critical:focus { background-color: #eb3b5a; } .action-btn i { margin-right: 6px; font-size: 0.8rem; } .node::before { content: ''; position: absolute; top: -20px; left: 50%; width: 2px; height: 20px; background-color: #dfe6e9; } .node:first-child::before { display: none; } .progressbar { height: 6px; background-color: #e9ecef; border-radius: 3px; position: relative; margin: 24px 0; overflow: hidden; } .progress { position: absolute; top: 0; left: 0; height: 100%; background: linear-gradient(90deg, #4b7bec, #3867d6); width: 0%; transition: width 0.5s ease; border-radius: 3px; } .connecter { position: absolute; top: 100%; left: 50%; width: 2px; height: 20px; background-color: #dfe6e9; z-index: 1; } .connecter::after { content: ''; position: absolute; bottom: -6px; left: -4px; width: 10px; height: 10px; border-bottom: 2px solid #dfe6e9; border-right: 2px solid #dfe6e9; transform: rotate(45deg); } .hidden { display: none; } .tag { position: absolute; top: 0; right: 0; padding: 4px 8px; font-size: 0.7rem; font-weight: 700; color: white; text-transform: uppercase; border-bottom-left-radius: 8px; } .tag-critical { background-color: #fc5c65; } .tag-urgent { background-color: #fd9644; } .tag-routine { background-color: #26de81; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(252, 92, 101, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(252, 92, 101, 0); } 100% { box-shadow: 0 0 0 0 rgba(252, 92, 101, 0); } } .node.critical { animation: pulse 2s infinite; border-left: 4px solid #fc5c65; } .info-icon { display: inline-flex; width: 18px; height: 18px; border-radius: 50%; background-color: #dfe6e9; color: #636e72; font-size: 0.7rem; align-items: center; justify-content: center; margin-left: 6px; cursor: pointer; position: relative; } .info-tooltip { position: absolute; top: calc(100% + 10px); left: 50%; transform: translateX(-50%); width: 200px; background-color: #2d3436; color: white; padding: 8px 12px; border-radius: 6px; font-size: 0.8rem; z-index: 10; opacity: 0; visibility: hidden; transition: all 0.2s ease; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); } .info-tooltip::before { content: ''; position: absolute; top: -6px; left: 50%; transform: translateX(-50%); border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 6px solid #2d3436; } .info-icon:hover .info-tooltip { opacity: 1; visibility: visible; } @media (max-width: 480px) { h1 { font-size: 1.4rem; } .node { margin: 15px auto; } .node-content { padding: 12px; } .node-title { font-size: 1rem; } .action-btn { padding: 6px 12px; font-size: 0.8rem; } } .restart-btn { position: fixed; bottom: 20px; right: 20px; background-color: #4b7bec; color: white; border: none; border-radius: 50%; width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 12px rgba(75, 123, 236, 0.4); cursor: pointer; transition: all 0.2s ease; opacity: 0; transform: translateY(20px); z-index: 100; } .restart-btn.visible { opacity: 1; transform: translateY(0); } .restart-btn:hover { background-color: #3867d6; transform: translateY(-2px); box-shadow: 0 6px 16px rgba(75, 123, 236, 0.5); } .path-indicator { display: flex; padding: 10px 15px; background-color: white; border-radius: 6px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); gap: 6px; margin-bottom: 15px; flex-wrap: wrap; transition: all 0.3s ease; } .path-step { font-size: 0.75rem; display: flex; align-items: center; color: #636e72; } .path-step:not(:last-child)::after { content: '›'; margin: 0 6px; color: #b2bec3; } .path-step.active { font-weight: 500; color: #4b7bec; } </style> </head> <body> <div class="container"> <h1>Clinical Decision Pathway</h1> <div class="path-indicator" id="pathIndicator"> <div class="path-step active">Patient Assessment</div> </div> <div class="progressbar"> <div class="progress" id="progress"></div> </div> <div class="flowchart" id="flowchart"> <div class="node" id="node-1"> <div class="node-content"> <div class="node-header"> <div class="node-icon icon-assessment"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M20 11.08V8l-6-6H6a2 2 0 0 0-2 2v16c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2v-3.08"></path> <path d="M14 3v5h5M12 18h4M12 14h4M12 10h4"></path> </svg> </div> <h3 class="node-title">Initial Patient Assessment</h3> </div> <p class="node-description">Begin by evaluating the patient's primary symptoms and vital signs. Record key measurements including temperature, blood pressure, heart rate, and respiratory rate.</p> <div class="node-actions"> <button class="action-btn primary" data-next="node-2"> <i>→</i> Begin Assessment </button> </div> </div> </div> </div> <button class="restart-btn" id="restartBtn"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path> <path d="M3 3v5h5"></path> </svg> </button> </div> <script> const nodes = { 'node-1': { title: 'Initial Patient Assessment', description: 'Begin by evaluating the patient\'s primary symptoms and vital signs. Record key measurements including temperature, blood pressure, heart rate, and respiratory rate.', icon: 'icon-assessment', actions: [ { text: 'Begin Assessment', next: 'node-2', type: 'primary' } ], pathStep: 'Patient Assessment' }, 'node-2': { title: 'Symptom Evaluation', description: 'Determine the nature of the patient\'s primary complaint. Select the predominant symptom category for further assessment.', icon: 'icon-assessment', actions: [ { text: 'Respiratory Distress', next: 'node-3', type: 'critical' }, { text: 'Chest Pain', next: 'node-4', type: 'critical' }, { text: 'Abdominal Pain', next: 'node-5' }, { text: 'Neurological Symptoms', next: 'node-6' } ], pathStep: 'Symptom Evaluation' }, 'node-3': { title: 'Respiratory Distress Assessment', description: 'Patient presents with difficulty breathing. Evaluate severity and possible causes.', icon: 'icon-assessment', tag: { text: 'Critical', class: 'tag-critical' }, critical: true, info: 'For SpO2 < 90% or severe respiratory distress, consider immediate intervention', actions: [ { text: 'Mild (SpO2 > 94%)', next: 'node-3a' }, { text: 'Moderate (SpO2 90-94%)', next: 'node-3b' }, { text: 'Severe (SpO2 < 90%)', next: 'node-3c', type: 'critical' } ], pathStep: 'Respiratory Assessment' }, 'node-3a': { title: 'Mild Respiratory Distress', description: 'Patient has mild respiratory symptoms with good oxygen saturation. Consider the following interventions.', icon: 'icon-treatment', actions: [ { text: 'Administer Supplemental O₂', next: 'node-3d' }, { text: 'Order Chest X-ray', next: 'node-3d' }, { text: 'Bronchodilator Therapy', next: 'node-3d' } ], pathStep: 'Treatment Plan' }, 'node-3b': { title: 'Moderate Respiratory Distress', description: 'Patient has moderate respiratory distress requiring prompt intervention.', icon: 'icon-treatment', tag: { text: 'Urgent', class: 'tag-urgent' }, actions: [ { text: 'High-Flow O₂ Therapy', next: 'node-3d' }, { text: 'Order ABG Analysis', next: 'node-3d' }, { text: 'IV Corticosteroids', next: 'node-3d' } ], pathStep: 'Treatment Plan' }, 'node-3c': { title: 'Severe Respiratory Distress', description: 'Patient has severe respiratory compromise requiring immediate intervention.', icon: 'icon-critical', tag: { text: 'Critical', class: 'tag-critical' }, critical: true, actions: [ { text: 'Activate Rapid Response', next: 'node-3e', type: 'critical' }, { text: 'Prepare for Intubation', next: 'node-3e', type: 'critical' }, { text: 'ICU Consultation', next: 'node-3e', type: 'critical' } ], pathStep: 'Emergency Protocol' }, 'node-3d': { title: 'Respiratory Treatment Plan', description: 'Implement the selected interventions and monitor response. Reassess in 30 minutes.', icon: 'icon-treatment', actions: [ { text: 'Patient Improving', next: 'node-7' }, { text: 'No Improvement', next: 'node-3c', type: 'critical' } ], pathStep: 'Response Monitoring' }, 'node-3e': { title: 'Critical Care Protocol', description: 'Patient requires critical care management. The rapid response team has been notified.', icon: 'icon-critical', tag: { text: 'Critical', class: 'tag-critical' }, critical: true, actions: [ { text: 'Transfer to ICU', next: 'node-8', type: 'critical' } ], pathStep: 'Critical Care' }, 'node-4': { title: 'Chest Pain Evaluation', description: 'Patient presents with chest pain. Assess characteristics and associated symptoms.', icon: 'icon-assessment', tag: { text: 'Critical', class: 'tag-critical' }, critical: true, actions: [ { text: 'Suspected Cardiac', next: 'node-4a', type: 'critical' }, { text: 'Suspected Pulmonary', next: 'node-4b' }, { text: 'Musculoskeletal', next: 'node-4c' } ], pathStep: 'Chest Pain Evaluation' }, 'node-4a': { title: 'Cardiac Chest Pain', description: 'Patient has symptoms consistent with cardiac origin. Implement cardiac protocol.', icon: 'icon-critical', tag: { text: 'Critical', class: 'tag-critical' }, critical: true, actions: [ { text: 'ECG & Cardiac Enzymes', next: 'node-4d', type: 'critical' }, { text: 'Administer Aspirin', next: 'node-4d', type: 'critical' }, { text: 'Cardiology Consult', next: 'node-4d', type: 'critical' } ], pathStep: 'Cardiac Protocol' }, 'node-4b': { title: 'Pulmonary Chest Pain', description: 'Patient has symptoms suggesting pulmonary origin such as pleuritic pain or dyspnea.', icon: 'icon-assessment', tag: { text: 'Urgent', class: 'tag-urgent' }, actions: [ { text: 'D-dimer & Chest CT', next: 'node-4e' }, { text: 'Oxygen Therapy', next: 'node-4e' } ], pathStep: 'Pulmonary Assessment' }, 'node-4c': { title: 'Musculoskeletal Chest Pain', description: 'Patient has pain characteristic of musculoskeletal origin with reproducible tenderness.', icon: 'icon-assessment', actions: [ { text: 'Analgesic Therapy', next: 'node-7' }, { text: 'Rule Out Cardiac Causes', next: 'node-4a' } ], pathStep: 'Pain Management' }, 'node-4d': { title: 'Cardiac Treatment Protocol', description: 'Implement cardiac interventions based on ECG and cardiac enzyme results.', icon: 'icon-treatment', tag: { text: 'Critical', class: 'tag-critical' }, critical: true, actions: [ { text: 'STEMI Protocol', next: 'node-8', type: 'critical' }, { text: 'ACS Management', next: 'node-8', type: 'critical' }, { text: 'Low-Risk Cardiac', next: 'node-7' } ], pathStep: 'Cardiac Treatment' }, 'node-4e': { title: 'Pulmonary Assessment Results', description: 'Evaluate the results of pulmonary diagnostic tests and determine management.', icon: 'icon-decision', actions: [ { text: 'Pulmonary Embolism', next: 'node-8', type: 'critical' }, { text: 'Pneumonia', next: 'node-7' }, { text: 'Negative Findings', next: 'node-7' } ], pathStep: 'Diagnostic Results' }, 'node-5': { title: 'Abdominal Pain Assessment', description: 'Evaluate the characteristics, location, and severity of abdominal pain.', icon: 'icon-assessment', actions: [ { text: 'Upper Abdominal Pain', next: 'node-5a' }, { text: 'Lower Abdominal Pain', next: 'node-5b' }, { text: 'Diffuse Abdominal Pain', next: 'node-5c' } ], pathStep: 'Abdominal Assessment' }, 'node-5a': { title: 'Upper Abdominal Pain', description: 'Patient has pain in the upper abdomen. Consider the following diagnostic pathways.', icon: 'icon-assessment', actions: [ { text: 'Gastric/Biliary Workup', next: 'node-5d' }, { text: 'Pancreatic Workup', next: 'node-5d' }, { text: 'Cardiac Evaluation', next: 'node-4a' } ], pathStep: 'Upper Abdominal Evaluation' }, 'node-5b': { title: 'Lower Abdominal Pain', description: 'Patient has pain in the lower abdomen. Consider specific diagnostic tests.', icon: 'icon-assessment', actions: [ { text: 'Appendicitis Workup', next: 'node-5e' }, { text: 'Gynecological Causes', next: 'node-5e' }, { text: 'Urinary Tract', next: 'node-5e' } ], pathStep: 'Lower Abdominal Evaluation' }, 'node-5c': { title: 'Diffuse Abdominal Pain', description: 'Patient has generalized abdominal pain. Consider broader differential diagnoses.', icon: 'icon-assessment', tag: { text: 'Urgent', class: 'tag-urgent' }, actions: [ { text: 'Intestinal Obstruction', next: 'node-5f' }, { text: 'Inflammatory Process', next: 'node-5f' }, { text: 'Vascular Causes', next: 'node-5f', type: 'critical' } ], pathStep: 'Abdominal Evaluation' }, 'node-5d': { title: 'Upper Abdominal Diagnosis', description: 'Based on laboratory and imaging results, determine diagnosis and treatment.', icon: 'icon-decision', actions: [ { text: 'Cholecystitis', next: 'node-7' }, { text: 'Pancreatitis', next: 'node-7' }, { text: 'Peptic Ulcer Disease', next: 'node-7' } ], pathStep: 'Diagnosis & Treatment' }, 'node-5e': { title: 'Lower Abdominal Diagnosis', description: 'Based on evaluation, determine the most likely diagnosis and treatment plan.', icon: 'icon-decision', actions: [ { text: 'Appendicitis', next: 'node-8' }, { text: 'PID/Ovarian Issue', next: 'node-7' }, { text: 'Urinary Tract Infection', next: 'node-7' } ], pathStep: 'Diagnosis & Treatment' }, 'node-5f': { title: 'Diffuse Abdominal Diagnosis', description: 'Based on comprehensive evaluation, determine diagnosis and urgency level.', icon: 'icon-decision', actions: [ { text: 'Bowel Obstruction', next: 'node-8' }, { text: 'Mesenteric Ischemia', next: 'node-8', type: 'critical' }, { text: 'Gastroenteritis', next: 'node-7' } ], pathStep: 'Diagnosis & Treatment' }, 'node-6': { title: 'Neurological Assessment', description: 'Evaluate patient presenting with neurological symptoms. Conduct a focused neurological exam.', icon: 'icon-assessment', actions: [ { text: 'Headache', next: 'node-6a' }, { text: 'Focal Deficits', next: 'node-6b', type: 'critical' }, { text: 'Altered Mental Status', next: 'node-6c', type: 'critical' } ], pathStep: 'Neurological Assessment' }, 'node-6a': { title: 'Headache Evaluation', description: 'Assess characteristics of headache including onset, quality, and associated symptoms.', icon: 'icon-assessment', actions: [ { text: 'Migraine Pattern', next: 'node-7' }, { text: 'Thunder-clap Onset', next: 'node-6d', type: 'critical' }, { text: 'With Visual Changes', next: 'node-6d' } ], pathStep: 'Headache Evaluation' }, 'node-6b': { title: 'Focal Neurological Deficits', description: 'Patient presents with focal neurological deficits. Implement stroke protocol if indicated.', icon: 'icon-critical', tag: { text: 'Critical', class: 'tag-critical' }, critical: true, actions: [ { text: 'Activate Stroke Alert', next: 'node-6e', type: 'critical' }, { text: 'Urgent Neuroimaging', next: 'node-6e', type: 'critical' } ], pathStep: 'Stroke Protocol' }, 'node-6c': { title: 'Altered Mental Status', description: 'Patient has altered level of consciousness. Assess for immediate threats to life.', icon: 'icon-critical', tag: { text: 'Critical', class: 'tag-critical' }, critical: true, actions: [ { text: 'Check Glucose/Naloxone', next: 'node-6f', type: 'critical' }, { text: 'Neuroimaging', next: 'node-6f', type: 'critical' }, { text: 'Lumbar Puncture', next: 'node-6f' } ], pathStep: 'Emergency Protocol' }, 'node-6d': { title: 'Headache Assessment Results', description: 'Based on assessment and neuroimaging, determine diagnosis and treatment plan.', icon: 'icon-decision', actions: [ { text: 'Subarachnoid Hemorrhage', next: 'node-8', type: 'critical' }, { text: 'Migraine with Aura', next: 'node-7' }, { text: 'Tension Headache', next: 'node-7' } ], pathStep: 'Diagnosis & Treatment' }, 'node-6e': { title: 'Stroke Evaluation Results', description: 'Based on neuroimaging and clinical evaluation, determine stroke subtype and treatment.', icon: 'icon-critical', tag: { text: 'Critical', class: 'tag-critical' }, critical: true, actions: [ { text: 'Ischemic - tPA Candidate', next: 'node-8', type: 'critical' }, { text: 'Hemorrhagic Stroke', next: 'node-8', type: 'critical' }, { text: 'Stroke Mimic', next: 'node-7' } ], pathStep: 'Stroke Management' }, 'node-6f': { title: 'Altered Mental Status Results', description: 'Based on diagnostic workup, determine cause of altered mental status.', icon: 'icon-decision', tag: { text: 'Urgent', class: 'tag-urgent' }, actions: [ { text: 'Metabolic Encephalopathy', next: 'node-7' }, { text: 'Intracranial Pathology', next: 'node-8', type: 'critical' }, { text: 'Seizure/Post-ictal', next: 'node-7' } ], pathStep: 'Diagnosis & Treatment' }, 'node-7': { title: 'Non-Emergent Treatment Plan', description: 'Implement appropriate treatment protocol based on diagnosis. Patient requires monitoring but not critical intervention.', icon: 'icon-treatment', tag: { text: 'Routine', class: 'tag-routine' }, actions: [ { text: 'Admission to Med/Surg', next: 'node-9' }, { text: 'Outpatient Management', next: 'node-10' } ], pathStep: 'Treatment Plan' }, 'node-8': { title: 'Emergency Intervention', description: 'Patient requires immediate intervention or surgical consultation based on critical diagnosis.', icon: 'icon-critical', tag: { text: 'Critical', class: 'tag-critical' }, critical: true, actions: [ { text: 'Surgical Consultation', next: 'node-11', type: 'critical' }, { text: 'ICU Admission', next: 'node-12', type: 'critical' } ], pathStep: 'Emergency Protocol' }, 'node-9': { title: 'Inpatient Management', description: 'Patient admitted to medical/surgical unit for continued treatment and monitoring.', icon: 'icon-treatment', actions: [ { text: 'Complete Care Plan', next: 'node-13' } ], pathStep: 'Inpatient Care' }, 'node-10': { title: 'Outpatient Management', description: 'Patient stable for discharge with outpatient follow-up and treatment plan.', icon: 'icon-treatment', actions: [ { text: 'Provide Discharge Plan', next: 'node-14' } ], pathStep: 'Discharge Planning' }, 'node-11': { title: 'Surgical Intervention', description: 'Surgical team consulted and surgical intervention planned based on critical diagnosis.', icon: 'icon-critical', tag: { text: 'Critical', class: 'tag-critical' }, actions: [ { text: 'Prepare for Surgery', next: 'node-15', type: 'critical' } ], pathStep: 'Surgical Protocol' }, 'node-12': { title: 'ICU Management', description: 'Patient transferred to Intensive Care Unit for critical care management.', icon: 'icon-critical', tag: { text: 'Critical', class: 'tag-critical' }, actions: [ { text: 'Implement ICU Protocol', next: 'node-16', type: 'critical' } ], pathStep: 'Critical Care' }, 'node-13': { title: 'Complete Inpatient Care', description: 'Patient has completed inpatient treatment course. Prepare discharge planning.', icon: 'icon-treatment', actions: [ { text: 'Discharge Planning', next: 'node-14' } ], pathStep: 'Care Completion' }, 'node-14': { title: 'Discharge Protocol', description: 'Implement discharge protocol including medication reconciliation, patient education, and follow-up appointment scheduling.', icon: 'icon-treatment', actions: [ { text: 'Complete Discharge', next: 'node-17' } ], pathStep: 'Discharge' }, 'node-15': { title: 'Post-Surgical Care', description: 'Patient has undergone surgical intervention. Implement post-operative care protocol.', icon: 'icon-treatment', actions: [ { text: 'Manage Post-Op Care', next: 'node-13' } ], pathStep: 'Post-Surgical Care' }, 'node-16': { title: 'ICU Treatment Course', description: 'Patient receiving critical care in ICU. Monitor response to interventions.', icon: 'icon-treatment', tag: { text: 'Critical', class: 'tag-critical' }, actions: [ { text: 'Condition Improving', next: 'node-13' }, { text: 'Requires Extended ICU', next: 'node-16' } ], pathStep: 'ICU Care' }, 'node-17': { title: 'Care Pathway Complete', description: 'Patient has completed the clinical decision pathway with appropriate diagnosis, treatment, and follow-up plan.', icon: 'icon-assessment', actions: [ { text: 'Start New Assessment', next: 'node-1' } ], pathStep: 'Completed' } }; const flowchart = document.getElementById('flowchart'); const progress = document.getElementById('progress'); const pathIndicator = document.getElementById('pathIndicator'); const restartBtn = document.getElementById('restartBtn'); let currentNode = 'node-1'; let pathSteps = []; function createNode(id) { const nodeData = nodes[id]; if (!nodeData) return; const node = document.createElement('div'); node.className = 'node'; node.id = id; if (nodeData.critical) node.classList.add('critical'); let nodeContent = ` <div class="node-content"> <div class="node-header"> <div class="node-icon ${nodeData.icon}"> ${getIconSVG(nodeData.icon)} </div> <h3 class="node-title">${nodeData.title}`; if (nodeData.info) { nodeContent += ` <span class="info-icon">i <span class="info-tooltip">${nodeData.info}</span> </span>`; } nodeContent += `</h3> </div> <p class="node-description">${nodeData.description}</p> <div class="node-actions">`; nodeData.actions.forEach(action => { const btnClass = action.type ? `action-btn ${action.type}` : 'action-btn'; nodeContent += ` <button class="${btnClass}" data-next="${action.next
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Agile Project Management Flowchart</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f9f9f9; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; overflow: hidden; } .container { width: 650px; height: 650px; position: relative; background-color: #fff; border-radius: 12px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); overflow: hidden; padding: 15px; } .header { padding: 10px 15px; background: linear-gradient(135deg, #6366F1, #8B5CF6); border-radius: 8px; color: white; margin-bottom: 20px; box-shadow: 0 4px 12px rgba(131, 94, 246, 0.2); position: relative; overflow: hidden; } .header h1 { font-size: 20px; font-weight: 600; } .header p { font-size: 14px; opacity: 0.9; margin-top: 5px; } .header::before { content: ''; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: repeating-linear-gradient( 45deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0.03) 10px, rgba(255, 255, 255, 0.06) 10px, rgba(255, 255, 255, 0.06) 20px ); animation: patternMove 30s linear infinite; z-index: 0; } .header * { position: relative; z-index: 1; } @keyframes patternMove { 0% { transform: translate(0, 0); } 100% { transform: translate(50px, 50px); } } .flowchart-container { height: calc(100% - 110px); position: relative; overflow: auto; padding: 10px; } .flowchart-grid { width: 2000px; height: 1500px; background-size: 20px 20px; background-image: linear-gradient(to right, rgba(0, 0, 0, 0.05) 1px, transparent 1px), linear-gradient(to bottom, rgba(0, 0, 0, 0.05) 1px, transparent 1px); position: relative; } .node { position: absolute; background-color: white; border-radius: 6px; padding: 12px; width: 160px; min-height: 80px; cursor: move; user-select: none; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); transition: transform 0.2s, box-shadow 0.2s; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; } .node.product-backlog { background: linear-gradient(135deg, #F472B6, #EC4899); color: white; top: 30px; left: 50px; } .node.sprint-planning { background: linear-gradient(135deg, #60A5FA, #3B82F6); color: white; top: 30px; left: 270px; } .node.sprint-backlog { background: linear-gradient(135deg, #34D399, #10B981); color: white; top: 30px; left: 490px; } .node.daily-scrum { background: linear-gradient(135deg, #A78BFA, #8B5CF6); color: white; top: 160px; left: 490px; } .node.development { background: linear-gradient(135deg, #FBBF24, #F59E0B); color: white; top: 160px; left: 270px; } .node.testing { background: linear-gradient(135deg, #F87171, #EF4444); color: white; top: 160px; left: 50px; } .node.sprint-review { background: linear-gradient(135deg, #6EE7B7, #10B981); color: white; top: 290px; left: 50px; } .node.sprint-retrospective { background: linear-gradient(135deg, #C084FC, #A855F7); color: white; top: 290px; left: 270px; } .node.product-increment { background: linear-gradient(135deg, #38BDF8, #0EA5E9); color: white; top: 290px; left: 490px; } .node:hover { transform: translateY(-5px); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.12); } .node-title { font-weight: 600; font-size: 14px; margin-bottom: 5px; } .node-description { font-size: 11px; opacity: 0.9; } .node.dragging { opacity: 0.8; z-index: 1000; } .node .collaborators { position: absolute; top: -8px; right: -8px; display: flex; } .collaborator { width: 20px; height: 20px; border-radius: 50%; background-color: #6366F1; border: 2px solid white; margin-left: -5px; display: flex; align-items: center; justify-content: center; font-size: 10px; color: white; font-weight: bold; } .edge { position: absolute; pointer-events: none; z-index: -1; } .control-panel { padding: 10px; background-color: #f1f5f9; border-radius: 8px; margin-top: 20px; display: flex; justify-content: space-between; align-items: center; } .zoom-controls button { background-color: white; border: 1px solid #e2e8f0; border-radius: 4px; padding: 5px 10px; cursor: pointer; font-size: 14px; margin-right: 5px; transition: all 0.2s; } .zoom-controls button:hover { background-color: #f8fafc; border-color: #cbd5e1; } .progress-indicator { display: flex; align-items: center; } .progress-label { font-size: 12px; margin-right: 8px; } .progress-bar { height: 8px; width: 100px; background-color: #e2e8f0; border-radius: 4px; overflow: hidden; } .progress-fill { height: 100%; background: linear-gradient(90deg, #6366F1, #8B5CF6); width: 35%; border-radius: 4px; transition: width 1s ease-in-out; } .tooltip { position: absolute; background-color: rgba(0, 0, 0, 0.8); color: white; padding: 5px 10px; border-radius: 4px; font-size: 12px; pointer-events: none; opacity: 0; transition: opacity 0.3s; z-index: 1000; } .pulse-animation { animation: pulse 2s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(131, 94, 246, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(131, 94, 246, 0); } 100% { box-shadow: 0 0 0 0 rgba(131, 94, 246, 0); } } .snap-indicator { position: absolute; width: 20px; height: 20px; border-radius: 50%; background-color: rgba(131, 94, 246, 0.3); pointer-events: none; transform: translate(-50%, -50%); z-index: 1001; opacity: 0; transition: opacity 0.2s; } @media (max-width: 700px) { .container { width: 100%; height: 100%; border-radius: 0; } .node { width: 140px; min-height: 70px; padding: 8px; } .node-title { font-size: 12px; } .node-description { font-size: 10px; } } </style> </head> <body> <div class="container"> <div class="header"> <h1>Agile Sprint Workflow</h1> <p>Drag nodes to organize your team's iterative development process</p> </div> <div class="flowchart-container"> <div class="flowchart-grid" id="flowchart-grid"> <div class="node product-backlog" data-id="1"> <div class="node-title">Product Backlog</div> <div class="node-description">Prioritized list of all desired features</div> <div class="collaborators"> <div class="collaborator">PO</div> </div> </div> <div class="node sprint-planning" data-id="2"> <div class="node-title">Sprint Planning</div> <div class="node-description">Select tasks for upcoming sprint</div> <div class="collaborators"> <div class="collaborator">SM</div> <div class="collaborator">T</div> </div> </div> <div class="node sprint-backlog" data-id="3"> <div class="node-title">Sprint Backlog</div> <div class="node-description">Tasks committed for current sprint</div> <div class="collaborators"> <div class="collaborator">T</div> </div> </div> <div class="node daily-scrum" data-id="4"> <div class="node-title">Daily Scrum</div> <div class="node-description">15-min sync on progress & blockers</div> <div class="collaborators"> <div class="collaborator">SM</div> <div class="collaborator">T</div> </div> </div> <div class="node development pulse-animation" data-id="5"> <div class="node-title">Development</div> <div class="node-description">Implementation of sprint tasks</div> <div class="collaborators"> <div class="collaborator">D</div> </div> </div> <div class="node testing" data-id="6"> <div class="node-title">Testing</div> <div class="node-description">Quality assurance & verification</div> <div class="collaborators"> <div class="collaborator">QA</div> </div> </div> <div class="node sprint-review" data-id="7"> <div class="node-title">Sprint Review</div> <div class="node-description">Demo completed features to stakeholders</div> <div class="collaborators"> <div class="collaborator">ALL</div> </div> </div> <div class="node sprint-retrospective" data-id="8"> <div class="node-title">Sprint Retrospective</div> <div class="node-description">Process improvement discussion</div> <div class="collaborators"> <div class="collaborator">SM</div> <div class="collaborator">T</div> </div> </div> <div class="node product-increment" data-id="9"> <div class="node-title">Product Increment</div> <div class="node-description">Potentially shippable product update</div> <div class="collaborators"> <div class="collaborator">PO</div> </div> </div> </div> </div> <div class="control-panel"> <div class="zoom-controls"> <button id="zoom-in">+</button> <button id="zoom-out">-</button> <button id="reset">Reset</button> </div> <div class="progress-indicator"> <div class="progress-label">Sprint Progress:</div> <div class="progress-bar"> <div class="progress-fill" id="progress-fill"></div> </div> </div> </div> </div> <div class="tooltip" id="tooltip"></div> <div class="snap-indicator" id="snap-indicator"></div> <script> document.addEventListener('DOMContentLoaded', function() { const nodes = document.querySelectorAll('.node'); const tooltip = document.getElementById('tooltip'); const snapIndicator = document.getElementById('snap-indicator'); const grid = document.getElementById('flowchart-grid'); const flowchartContainer = document.querySelector('.flowchart-container'); const progressFill = document.getElementById('progress-fill'); let isDragging = false; let draggedNode = null; let initialX = 0; let initialY = 0; let offsetX = 0; let offsetY = 0; let gridSize = 20; // Grid cell size for snap let scale = 1; // Draw arrows between nodes using SVG function createSVGEdges() { // Remove existing edges document.querySelectorAll('.edge').forEach(edge => edge.remove()); // Define connections (from node id -> to node id) const connections = [ {from: 1, to: 2}, {from: 2, to: 3}, {from: 3, to: 4}, {from: 4, to: 5}, {from: 5, to: 6}, {from: 6, to: 7}, {from: 7, to: 8}, {from: 8, to: 9}, {from: 9, to: 1} ]; connections.forEach(conn => { const fromNode = document.querySelector(`.node[data-id="${conn.from}"]`); const toNode = document.querySelector(`.node[data-id="${conn.to}"]`); if (fromNode && toNode) { const fromRect = fromNode.getBoundingClientRect(); const toRect = toNode.getBoundingClientRect(); const gridRect = grid.getBoundingClientRect(); // Adjust coordinates relative to grid const fromX = fromRect.left - gridRect.left + fromRect.width / 2 + grid.scrollLeft; const fromY = fromRect.top - gridRect.top + fromRect.height / 2 + grid.scrollTop; const toX = toRect.left - gridRect.left + toRect.width / 2 + grid.scrollLeft; const toY = toRect.top - gridRect.top + toRect.height / 2 + grid.scrollTop; drawSVGArrow(fromX, fromY, toX, toY); } }); } function drawSVGArrow(fromX, fromY, toX, toY) { // Calculate the angle const angle = Math.atan2(toY - fromY, toX - fromX); // Calculate marker coordinates const markerSize = 8; const markerX = toX - markerSize * Math.cos(angle); const markerY = toY - markerSize * Math.sin(angle); // Create SVG element const svgNS = "http://www.w3.org/2000/svg"; const svg = document.createElementNS(svgNS, "svg"); svg.setAttribute("class", "edge"); svg.style.left = "0"; svg.style.top = "0"; svg.style.width = "100%"; svg.style.height = "100%"; // Create path element for line const path = document.createElementNS(svgNS, "path"); path.setAttribute("d", `M${fromX},${fromY} L${markerX},${markerY}`); path.setAttribute("stroke", "#94a3b8"); path.setAttribute("stroke-width", "2"); path.setAttribute("fill", "none"); path.setAttribute("marker-end", "url(#arrowhead)"); // Create marker element for arrowhead const defs = document.createElementNS(svgNS, "defs"); const marker = document.createElementNS(svgNS, "marker"); marker.setAttribute("id", "arrowhead"); marker.setAttribute("markerWidth", "10"); marker.setAttribute("markerHeight", "7"); marker.setAttribute("refX", "0"); marker.setAttribute("refY", "3.5"); marker.setAttribute("orient", "auto"); const polygon = document.createElementNS(svgNS, "polygon"); polygon.setAttribute("points", "0 0, 10 3.5, 0 7"); polygon.setAttribute("fill", "#94a3b8"); marker.appendChild(polygon); defs.appendChild(marker); svg.appendChild(defs); svg.appendChild(path); grid.appendChild(svg); } // Show tooltip with node details function showTooltip(node, event) { const nodeTitle = node.querySelector('.node-title').textContent; const nodeDesc = node.querySelector('.node-description').textContent; tooltip.innerHTML = `<strong>${nodeTitle}</strong><br>${nodeDesc}`; tooltip.style.left = `${event.pageX + 10}px`; tooltip.style.top = `${event.pageY + 10}px`; tooltip.style.opacity = 1; } function hideTooltip() { tooltip.style.opacity = 0; } // Handle node drag function startDrag(e) { if (e.target.closest('.node')) { e.preventDefault(); isDragging = true; draggedNode = e.target.closest('.node'); // Add dragging class for visual feedback draggedNode.classList.add('dragging'); const rect = draggedNode.getBoundingClientRect(); // Calculate offset if (e.type === 'mousedown') { offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; initialX = e.clientX; initialY = e.clientY; } else { offsetX = e.touches[0].clientX - rect.left; offsetY = e.touches[0].clientY - rect.top; initialX = e.touches[0].clientX; initialY = e.touches[0].clientY; } } } function drag(e) { if (!isDragging) return; e.preventDefault(); let clientX, clientY; if (e.type === 'mousemove') { clientX = e.clientX; clientY = e.clientY; } else { clientX = e.touches[0].clientX; clientY = e.touches[0].clientY; } const gridRect = grid.getBoundingClientRect(); // Calculate new position let newLeft = (clientX - gridRect.left - offsetX + grid.scrollLeft) / scale; let newTop = (clientY - gridRect.top - offsetY + grid.scrollTop) / scale; // Snap to grid newLeft = Math.round(newLeft / gridSize) * gridSize; newTop = Math.round(newTop / gridSize) * gridSize; // Show snap indicator snapIndicator.style.opacity = 1; snapIndicator.style.left = `${newLeft + gridRect.left - grid.scrollLeft}px`; snapIndicator.style.top = `${newTop + gridRect.top - grid.scrollTop}px`; // Update node position draggedNode.style.left = `${newLeft}px`; draggedNode.style.top = `${newTop}px`; // Redraw edges createSVGEdges(); } function endDrag() { if (isDragging) { draggedNode.classList.remove('dragging'); isDragging = false; draggedNode = null; // Hide snap indicator snapIndicator.style.opacity = 0; // Final edge redraw createSVGEdges(); } } // Zoom functionality document.getElementById('zoom-in').addEventListener('click', function() { scale = Math.min(scale + 0.1, 2); grid.style.transform = `scale(${scale})`; grid.style.transformOrigin = 'top left'; }); document.getElementById('zoom-out').addEventListener('click', function() { scale = Math.max(scale - 0.1, 0.5); grid.style.transform = `scale(${scale})`; grid.style.transformOrigin = 'top left'; }); document.getElementById('reset').addEventListener('click', function() { scale = 1; grid.style.transform = `scale(${scale})`; grid.scrollLeft = 0; grid.scrollTop = 0; }); // Animate sprint progress let progress = 35; function animateProgress() { progress += 1; if (progress > 100) progress = 0; progressFill.style.width = `${progress}%`; // Add pulse effect to current phase node document.querySelectorAll('.node').forEach(node => { node.classList.remove('pulse-animation'); }); // Determine which node should pulse based on progress let pulsingNode; if (progress < 10) pulsingNode = '.product-backlog'; else if (progress < 20) pulsingNode = '.sprint-planning'; else if (progress < 30) pulsingNode = '.sprint-backlog'; else if (progress < 50) pulsingNode = '.development'; else if (progress < 70) pulsingNode = '.daily-scrum'; else if (progress < 80) pulsingNode = '.testing'; else if (progress < 90) pulsingNode = '.sprint-review'; else if (progress < 95) pulsingNode = '.sprint-retrospective'; else pulsingNode = '.product-increment'; document.querySelector(pulsingNode)?.classList.add('pulse-animation'); } // Event listeners grid.addEventListener('mousedown', startDrag); grid.addEventListener('touchstart', startDrag, { passive: false }); document.addEventListener('mousemove', drag); document.addEventListener('touchmove', drag, { passive: false }); document.addEventListener('mouseup', endDrag); document.addEventListener('touchend', endDrag); nodes.forEach(node => { node.addEventListener('mouseenter', (e) => showTooltip(node, e)); node.addEventListener('mouseleave', hideTooltip); }); // Initial setup createSVGEdges(); // Start progress animation setInterval(animateProgress, 1000); // Random collaborate activity simulation function simulateCollaboration() { const nodes = document.querySelectorAll('.node'); const randomNode = nodes[Math.floor(Math.random() * nodes.length)]; // Add a brief highlight randomNode.style.boxShadow = '0 0 0 3px rgba(99, 102, 241, 0.5)'; // Update collaborator const collaboratorsDiv = randomNode.querySelector('.collaborators'); const initials = ['PO', 'SM', 'D', 'QA', 'T']; const randomInitial = initials[Math.floor(Math.random() * initials.length)]; // Add collaborator with animation if not exists if (!Array.from(collaboratorsDiv.querySelectorAll('.collaborator')).some(c => c.textContent === randomInitial)) { const newCollaborator = document.createElement('div'); newCollaborator.className = 'collaborator'; newCollaborator.textContent = randomInitial; newCollaborator.style.transform = 'scale(0)'; collaboratorsDiv.appendChild(newCollaborator); setTimeout(() => { newCollaborator.style.transition = 'transform 0.3s'; newCollaborator.style.transform = 'scale(1)'; }, 10); } // Reset after animation setTimeout(() => { randomNode.style.boxShadow = ''; }, 1000); } setInterval(simulateCollaboration, 5000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Financial Decision-Making Flowchart</title> <style> :root { --primary-dark: #0d2338; --primary: #153e66; --primary-light: #2a5d8f; --secondary: #4c5c6b; --accent: #c0aa83; --light-gray: #e5e8ec; --white: #ffffff; --shadow: rgba(0, 0, 20, 0.1); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background: linear-gradient(135deg, var(--primary-dark), var(--primary)); color: var(--white); height: 100vh; display: flex; flex-direction: column; overflow: hidden; } .container { width: 100%; max-width: 700px; height: 100%; max-height: 700px; margin: 0 auto; padding: 1.5rem; display: flex; flex-direction: column; overflow: hidden; } header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; } .logo { display: flex; align-items: center; } .logo-icon { width: 32px; height: 32px; background: var(--accent); border-radius: 8px; position: relative; margin-right: 10px; box-shadow: 0 4px 12px var(--shadow); } .logo-icon::before, .logo-icon::after { content: ''; position: absolute; background: var(--primary-dark); } .logo-icon::before { width: 60%; height: 2px; top: 50%; left: 20%; transform: translateY(-50%); } .logo-icon::after { width: 2px; height: 60%; left: 50%; top: 20%; transform: translateX(-50%); } .logo h1 { font-size: 1.25rem; font-weight: 600; letter-spacing: 0.5px; } .controls { display: flex; gap: 1rem; } .btn { background: rgba(255, 255, 255, 0.1); border: none; padding: 0.5rem 1rem; border-radius: 4px; color: var(--white); font-weight: 500; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; gap: 0.5rem; } .btn:hover { background: rgba(255, 255, 255, 0.2); } .btn-primary { background: var(--accent); color: var(--primary-dark); } .btn-primary:hover { background: #d1bb94; } .btn i { font-size: 0.875rem; } .flowchart-container { flex: 1; overflow: auto; background: var(--white); border-radius: 8px; box-shadow: 0 8px 24px var(--shadow); position: relative; } .grid { position: absolute; width: 100%; height: 100%; background-size: 20px 20px; background-image: linear-gradient(to right, rgba(200, 205, 210, 0.1) 1px, transparent 1px), linear-gradient(to bottom, rgba(200, 205, 210, 0.1) 1px, transparent 1px); z-index: 1; } .flowchart { position: relative; padding: 2rem; min-width: 600px; min-height: 500px; z-index: 2; } .node { position: absolute; width: 180px; background: var(--white); border-radius: 6px; box-shadow: 0 4px 12px var(--shadow); padding: 1rem; transition: all 0.3s ease; cursor: pointer; z-index: 3; } .node:hover { transform: translateY(-4px); box-shadow: 0 8px 20px var(--shadow); } .node.expanded { width: 280px; z-index: 10; } .node-header { display: flex; align-items: center; margin-bottom: 0.5rem; } .node-icon { width: 24px; height: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 8px; font-size: 0.75rem; background: var(--light-gray); color: var(--primary); font-weight: bold; } .decision .node-icon { background: var(--primary-light); color: var(--white); } .risk .node-icon { background: #e57373; color: var(--white); } .outcome .node-icon { background: #81c784; color: var(--white); } .node-title { font-weight: 600; color: var(--primary-dark); font-size: 0.9rem; } .node-content { color: var(--secondary); font-size: 0.8rem; line-height: 1.4; } .node-details { margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--light-gray); font-size: 0.75rem; display: none; } .expanded .node-details { display: block; } .node-metrics { display: flex; gap: 1rem; margin-top: 0.5rem; } .metric { display: flex; flex-direction: column; background: var(--light-gray); padding: 0.5rem; border-radius: 4px; text-align: center; flex: 1; } .metric-value { font-weight: 600; color: var(--primary); font-size: 0.9rem; } .metric-label { font-size: 0.7rem; color: var(--secondary); } .connections { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 2; pointer-events: none; } .tooltip { position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); background: var(--primary-dark); color: var(--white); padding: 0.5rem 0.75rem; border-radius: 4px; font-size: 0.75rem; opacity: 0; transition: opacity 0.2s ease; pointer-events: none; white-space: nowrap; z-index: 100; } .tooltip::after { content: ''; position: absolute; top: 100%; left: 50%; transform: translateX(-50%); border-width: 5px; border-style: solid; border-color: var(--primary-dark) transparent transparent; } .node:hover .tooltip { opacity: 1; } .node-more { position: absolute; right: 8px; top: 8px; width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: var(--light-gray); color: var(--secondary); font-size: 0.8rem; cursor: pointer; transition: all 0.2s ease; } .node-more:hover { background: var(--primary-light); color: var(--white); } .expanded .node-more { transform: rotate(45deg); } .data-panel { position: absolute; right: 1.5rem; bottom: 1.5rem; width: 240px; background: var(--white); border-radius: 8px; box-shadow: 0 8px 24px var(--shadow); padding: 1rem; transform: translateY(120%); transition: transform 0.3s ease; z-index: 100; } .data-panel.active { transform: translateY(0); } .panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem; color: var(--primary-dark); font-weight: 600; } .panel-close { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: var(--light-gray); color: var(--secondary); font-size: 0.8rem; cursor: pointer; transition: all 0.2s ease; } .panel-close:hover { background: #e57373; color: var(--white); } .panel-content { font-size: 0.8rem; color: var(--secondary); } .data-row { display: flex; justify-content: space-between; padding: 0.5rem 0; border-bottom: 1px solid var(--light-gray); } .data-row:last-child { border-bottom: none; } .data-label { color: var(--secondary); } .data-value { color: var(--primary-dark); font-weight: 500; } .zoom-controls { position: absolute; left: 1.5rem; bottom: 1.5rem; display: flex; flex-direction: column; gap: 0.5rem; z-index: 100; } .zoom-btn { width: 32px; height: 32px; border-radius: 50%; background: var(--white); color: var(--primary); border: none; box-shadow: 0 2px 8px var(--shadow); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.2s ease; } .zoom-btn:hover { background: var(--primary); color: var(--white); } .loading { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); display: flex; align-items: center; justify-content: center; z-index: 1000; } .spinner { width: 40px; height: 40px; border: 3px solid rgba(21, 62, 102, 0.2); border-radius: 50%; border-top: 3px solid var(--primary); animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .notification { position: fixed; top: 1rem; left: 50%; transform: translateX(-50%); padding: 0.75rem 1.5rem; background: var(--white); color: var(--primary-dark); border-radius: 4px; box-shadow: 0 4px 12px var(--shadow); z-index: 1000; font-size: 0.875rem; opacity: 0; transition: opacity 0.3s ease; } .notification.show { opacity: 1; } @media (max-width: 600px) { .container { padding: 1rem; } .logo h1 { font-size: 1rem; } .btn { padding: 0.5rem; } .btn span { display: none; } .node { width: 150px; } .node.expanded { width: 220px; } .data-panel { width: calc(100% - 2rem); left: 1rem; right: 1rem; } } </style> </head> <body> <div class="container"> <header> <div class="logo"> <div class="logo-icon"></div> <h1>Financial Decision Navigator</h1> </div> <div class="controls"> <button class="btn" id="reset-btn"> <i>⟳</i> <span>Reset</span> </button> <button class="btn btn-primary" id="export-btn"> <i>↓</i> <span>Export</span> </button> </div> </header> <div class="flowchart-container"> <div class="grid"></div> <div class="flowchart" id="flowchart"> <!-- Nodes will be dynamically generated --> </div> <svg class="connections" id="connections"></svg> <div class="zoom-controls"> <button class="zoom-btn" id="zoom-in">+</button> <button class="zoom-btn" id="zoom-out">-</button> <button class="zoom-btn" id="zoom-reset">⊙</button> </div> <div class="data-panel" id="data-panel"> <div class="panel-header"> <span>Node Analysis</span> <div class="panel-close" id="panel-close">✕</div> </div> <div class="panel-content"> <div class="data-row"> <div class="data-label">Risk Score:</div> <div class="data-value">78/100</div> </div> <div class="data-row"> <div class="data-label">Expected Return:</div> <div class="data-value">12.4%</div> </div> <div class="data-row"> <div class="data-label">Time Horizon:</div> <div class="data-value">Medium (3-5y)</div> </div> <div class="data-row"> <div class="data-label">Volatility:</div> <div class="data-value">Medium-High</div> </div> <div class="data-row"> <div class="data-label">Recommendation:</div> <div class="data-value">Proceed with Caution</div> </div> </div> </div> </div> <div class="loading" id="loading"> <div class="spinner"></div> </div> <div class="notification" id="notification">Report has been exported successfully</div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Flowchart data const nodes = [ { id: 1, type: 'decision', title: 'Investment Allocation', content: 'Determine optimal asset allocation based on risk profile and market conditions.', details: 'Analysis of current market sentiment indicates moderate risk in equity markets with potential upside in tech and healthcare sectors.', metrics: [ { label: 'Risk', value: 'Medium' }, { label: 'Timeline', value: '1-2 Yrs' } ], x: 50, y: 50, connections: [2, 3] }, { id: 2, type: 'decision', title: 'Risk Assessment', content: 'Evaluate exposure to market volatility and liquidity constraints.', details: 'Quantitative analysis shows 68% probability of achieving target returns within acceptable volatility parameters.', metrics: [ { label: 'Confidence', value: '68%' }, { label: 'Impact', value: 'High' } ], x: 300, y: 50, connections: [4, 5] }, { id: 3, type: 'risk', title: 'Regulatory Compliance', content: 'Ensure adherence to SEC guidelines and internal governance standards.', details: 'Recent regulatory changes require enhanced disclosure for alternative investments. Compliance deadline: End of Q2.', metrics: [ { label: 'Status', value: 'Review' }, { label: 'Deadline', value: 'Q2 End' } ], x: 50, y: 200, connections: [6] }, { id: 4, type: 'risk', title: 'Market Volatility', content: 'Evaluate potential impact of current market conditions on portfolio.', details: 'VIX currently at 22.4, indicating moderate market anxiety. Recommend implementing hedging strategies for downside protection.', metrics: [ { label: 'VIX', value: '22.4' }, { label: 'Trend', value: 'Rising' } ], x: 300, y: 200, connections: [7] }, { id: 5, type: 'decision', title: 'Liquidity Analysis', content: 'Assess cash requirements against investment timeline.', details: 'Cash flow projections indicate sufficient liquidity for next 8 months. Consider maintaining 15% in short-term instruments.', metrics: [ { label: 'Cash', value: '15%' }, { label: 'Coverage', value: '8 Mos' } ], x: 450, y: 150, connections: [7] }, { id: 6, type: 'outcome', title: 'Conservative Strategy', content: 'Emphasis on capital preservation with moderate income generation.', details: 'Recommended allocation: 40% bonds, 25% blue-chip equities, 20% alternatives, 15% cash equivalents.', metrics: [ { label: 'Yield', value: '4.2%' }, { label: 'Risk', value: 'Low' } ], x: 150, y: 350, connections: [] }, { id: 7, type: 'outcome', title: 'Balanced Growth', content: 'Blended approach balancing growth opportunities with downside protection.', details: 'Recommended allocation: 50% equities (with sector tilts), 30% fixed income, 15% alternatives, 5% cash.', metrics: [ { label: 'Yield', value: '6.8%' }, { label: 'Risk', value: 'Medium' } ], x: 400, y: 350, connections: [] } ]; // Initialize flowchart const flowchart = document.getElementById('flowchart'); const connectionsElem = document.getElementById('connections'); const loading = document.getElementById('loading'); const dataPanel = document.getElementById('data-panel'); const notification = document.getElementById('notification'); let scale = 1; let offsetX = 0; let offsetY = 0; let isDragging = false; let startX, startY; // Create nodes and connections function renderFlowchart() { // Clear existing elements flowchart.innerHTML = ''; connectionsElem.innerHTML = ''; // Create nodes nodes.forEach(node => { const nodeElem = document.createElement('div'); nodeElem.className = `node ${node.type}`; nodeElem.dataset.id = node.id; nodeElem.style.left = `${node.x + offsetX}px`; nodeElem.style.top = `${node.y + offsetY}px`; // Create tooltip const tooltip = document.createElement('div'); tooltip.className = 'tooltip'; tooltip.textContent = `Decision Node ${node.id}: ${node.title}`; nodeElem.appendChild(tooltip); // Node header const nodeHeader = document.createElement('div'); nodeHeader.className = 'node-header'; const nodeIcon = document.createElement('div'); nodeIcon.className = 'node-icon'; nodeIcon.textContent = node.id; nodeHeader.appendChild(nodeIcon); const nodeTitle = document.createElement('div'); nodeTitle.className = 'node-title'; nodeTitle.textContent = node.title; nodeHeader.appendChild(nodeTitle); nodeElem.appendChild(nodeHeader); // Node content const nodeContent = document.createElement('div'); nodeContent.className = 'node-content'; nodeContent.textContent = node.content; nodeElem.appendChild(nodeContent); // Node expand button const nodeMore = document.createElement('div'); nodeMore.className = 'node-more'; nodeMore.textContent = '+'; nodeElem.appendChild(nodeMore); // Node details (initially hidden) const nodeDetails = document.createElement('div'); nodeDetails.className = 'node-details'; const nodeDetailText = document.createElement('p'); nodeDetailText.textContent = node.details; nodeDetails.appendChild(nodeDetailText); // Metrics const nodeMetrics = document.createElement('div'); nodeMetrics.className = 'node-metrics'; node.metrics.forEach(metric => { const metricElem = document.createElement('div'); metricElem.className = 'metric'; const metricValue = document.createElement('div'); metricValue.className = 'metric-value'; metricValue.textContent = metric.value; metricElem.appendChild(metricValue); const metricLabel = document.createElement('div'); metricLabel.className = 'metric-label'; metricLabel.textContent = metric.label; metricElem.appendChild(metricLabel); nodeMetrics.appendChild(metricElem); }); nodeDetails.appendChild(nodeMetrics); nodeElem.appendChild(nodeDetails); // Add event listener for expand/collapse nodeMore.addEventListener('click', (e) => { e.stopPropagation(); nodeElem.classList.toggle('expanded'); renderConnections(); // Re-render connections when node size changes }); // Add event listener for node click (show data panel) nodeElem.addEventListener('click', () => { dataPanel.classList.add('active'); }); flowchart.appendChild(nodeElem); }); renderConnections(); } // Draw connections between nodes function renderConnections() { connectionsElem.innerHTML = ''; nodes.forEach(node => { if (!node.connections || node.connections.length === 0) return; const sourceElem = document.querySelector(`.node[data-id="${node.id}"]`); if (!sourceElem) return; const sourceRect = sourceElem.getBoundingClientRect(); const flowchartRect = flowchart.getBoundingClientRect(); node.connections.forEach(targetId => { const targetElem = document.querySelector(`.node[data-id="${targetId}"]`); if (!targetElem) return; const targetRect = targetElem.getBoundingClientRect(); // Calculate positions relative to the SVG const x1 = sourceRect.left + sourceRect.width / 2 - flowchartRect.left; const y1 = sourceRect.top + sourceRect.height - flowchartRect.top; const x2 = targetRect.left + targetRect.width / 2 - flowchartRect.left; const y2 = targetRect.top - flowchartRect.top; // Create path with bezier curve const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); const midY = y1 + (y2 - y1) * 0.5; const d = `M${x1},${y1} C${x1},${midY} ${x2},${midY} ${x2},${y2}`; path.setAttribute('d', d); path.setAttribute('stroke', '#4c5c6b'); path.setAttribute('stroke-width', '2'); path.setAttribute('fill', 'none'); path.setAttribute('stroke-dasharray', '0'); path.setAttribute('marker-end', 'url(#arrow)'); // Create arrow marker if it doesn't exist let marker = document.getElementById('arrow'); if (!marker) { const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs'); marker = document.createElementNS('http://www.w3.org/2000/svg', 'marker'); marker.setAttribute('id', 'arrow'); marker.setAttribute('viewBox', '0 0 10 10'); marker.setAttribute('refX', '5'); marker.setAttribute('refY', '5'); marker.setAttribute('markerWidth', '6'); marker.setAttribute('markerHeight', '6'); marker.setAttribute('orient', 'auto-start-reverse'); const arrow = document.createElementNS('http://www.w3.org/2000/svg', 'path'); arrow.setAttribute('d', 'M 0 0 L 10 5 L 0 10 z'); arrow.setAttribute('fill', '#4c5c6b'); marker.appendChild(arrow); defs.appendChild(marker); connectionsElem.appendChild(defs); } connectionsElem.appendChild(path); // Animate the connection const length = path.getTotalLength(); path.setAttribute('stroke-dasharray', length); path.setAttribute('stroke-dashoffset', length); setTimeout(() => { path.style.transition = 'stroke-dashoffset 1s ease-in-out'; path.setAttribute('stroke-dashoffset', '0'); }, 100); }); }); } // Initialize zoom and pan functionality function initZoomPan() { const zoomIn = document.getElementById('zoom-in'); const zoomOut = document.getElementById('zoom-out'); const zoomReset = document.getElementById('zoom-reset'); zoomIn.addEventListener('click', () => { scale += 0.1; applyTransform(); }); zoomOut.addEventListener('click', () => { scale = Math.max(0.5, scale - 0.1); applyTransform(); }); zoomReset.addEventListener('click', () => { scale = 1; offsetX = 0; offsetY = 0; applyTransform(); }); // Enable dragging the flowchart flowchart.addEventListener('mousedown', (e) => { if (e.target === flowchart || e.target.classList.contains('grid')) { isDragging = true; startX = e.clientX; startY = e.clientY; flowchart.style.cursor = 'grabbing'; } }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; const dx = e.clientX - startX; const dy = e.clientY - startY; offsetX += dx / scale; offsetY += dy / scale; startX = e.clientX; startY = e.clientY; applyTransform(); }); document.addEventListener('mouseup', () => { isDragging = false; flowchart.style.cursor = 'default'; }); // Touch support flowchart.addEventListener('touchstart', (e) => { if (e.target === flowchart || e.target.classList.contains('grid')) { isDragging = true; startX = e.touches[0].clientX; startY = e.touches[0].clientY; } }); document.addEventListener('touchmove', (e) => { if (!isDragging) return; const dx = e.touches[0].clientX - startX; const dy = e.touches[0].clientY - startY; offsetX += dx / scale; offsetY += dy / scale; startX = e.touches[0].clientX; startY = e.touches[0].clientY; applyTransform(); }); document.addEventListener('touchend', () => { isDragging = false; }); } // Apply zoom and pan transformations function applyTransform() { flowchart.style.transform = `scale(${scale})`; nodes.forEach(node => { const nodeElem = document.querySelector(`.node[data-id="${node.id}"]`); if (nodeElem) { nodeElem.style.left = `${node.x + offsetX}px`; nodeElem.style.top = `${node.y + offsetY}px`; } }); renderConnections(); } // Initialize data panel functionality function initDataPanel() { const panelClose = document.getElementById('panel-close'); panelClose.addEventListener('click', () => { dataPanel.classList.remove('active'); }); } // Initialize export functionality function initExport() { const exportBtn = document.getElementById('export-btn'); exportBtn.addEventListener('click', () => { loading.style.display = 'flex'; // Simulate export process setTimeout(() => { loading.style.display = 'none'; notification.classList.add('show'); setTimeout(() => { notification.classList.remove('show'); }, 3000); }, 1500); }); } // Initialize reset functionality function initReset() { const resetBtn = document.getElementById('reset-btn'); resetBtn.addEventListener('click', () => { scale = 1; offsetX = 0; offsetY = 0; applyTransform(); // Reset expanded nodes document.querySelectorAll('.node.expanded').forEach(node => { node.classList.remove('expanded'); }); // Close data panel dataPanel.classList.remove('active'); }); } // Initialize application function init() { setTimeout(() => { loading.style.display = 'none'; renderFlowchart(); initZoomPan(); initDataPanel(); initExport(); initReset(); }, 1000); } init(); // Resize handler window.addEventListener('resize', renderConnections); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>E-commerce Customer Journey Flowchart</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f8f9fb; width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; overflow-x: hidden; } .container { width: 680px; height: 680px; padding: 20px; position: relative; overflow: hidden; border-radius: 12px; background: linear-gradient(135deg, #ffffff, #f2f5ff); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); } .header { text-align: center; margin-bottom: 15px; position: relative; z-index: 10; } h1 { color: #2e3192; font-size: 24px; font-weight: 700; margin-bottom: 10px; position: relative; display: inline-block; } h1::after { content: ''; position: absolute; bottom: -5px; left: 50%; transform: translateX(-50%); width: 40%; height: 3px; background: linear-gradient(90deg, #ff6b6b, #4ecdc4); border-radius: 2px; } .description { color: #555; font-size: 14px; margin-bottom: 15px; max-width: 90%; margin: 0 auto 20px; } .flowchart-container { position: relative; height: 520px; overflow: hidden; display: flex; flex-direction: column; align-items: center; } .node { width: 180px; padding: 15px; margin: 10px; border-radius: 12px; color: white; text-align: center; position: absolute; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1); z-index: 5; transform-origin: center; } .node:hover { transform: translateY(-5px) scale(1.05); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15); } .node.clicked { transform: scale(1.2); z-index: 100; } .node h3 { font-size: 16px; margin-bottom: 5px; font-weight: 600; } .node p { font-size: 12px; opacity: 0.9; } .node .icon { font-size: 24px; margin-bottom: 10px; } .node .stat { font-size: 11px; background-color: rgba(255, 255, 255, 0.2); padding: 3px 8px; border-radius: 10px; display: inline-block; margin-top: 8px; } .node-content { transform: scale(1); transition: transform 0.3s ease; } .node-tip { position: absolute; background-color: #fff; padding: 12px; border-radius: 8px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15); width: 220px; color: #333; font-size: 12px; line-height: 1.4; opacity: 0; visibility: hidden; transition: all 0.3s ease; z-index: 10; top: 50%; left: 50%; transform: translate(-50%, -50%); } .node-tip h4 { color: #2e3192; margin-bottom: 5px; font-size: 14px; } .node-tip ul { text-align: left; padding-left: 15px; } .node-tip li { margin-bottom: 4px; } .node.clicked .node-content { transform: scale(0); } .node.clicked .node-tip { opacity: 1; visibility: visible; } .close-tip { position: absolute; top: 5px; right: 5px; font-size: 16px; color: #888; cursor: pointer; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; border-radius: 50%; } .close-tip:hover { background-color: #f0f0f0; color: #333; } .connector { position: absolute; background-color: #cfd8dc; z-index: 1; transition: all 0.3s ease; } .connector.vertical { width: 2px; border-radius: 1px; } .connector.horizontal { height: 2px; border-radius: 1px; } .connector.active { background-color: #4ecdc4; box-shadow: 0 0 10px rgba(78, 205, 196, 0.5); } .node.discovery { background: linear-gradient(135deg, #ff6b6b, #ff8e8e); top: 10px; left: 240px; } .node.research { background: linear-gradient(135deg, #f7b733, #fc4a1a); top: 110px; left: 100px; } .node.consideration { background: linear-gradient(135deg, #6a11cb, #2575fc); top: 110px; left: 380px; } .node.purchase { background: linear-gradient(135deg, #00b09b, #96c93d); top: 230px; left: 240px; } .node.support { background: linear-gradient(135deg, #3a7bd5, #00d2ff); top: 350px; left: 100px; } .node.loyalty { background: linear-gradient(135deg, #8e2de2, #4a00e0); top: 350px; left: 380px; } .node.advocacy { background: linear-gradient(135deg, #0ba360, #3cba92); top: 450px; left: 240px; } .analytics-panel { position: absolute; bottom: 15px; left: 50%; transform: translateX(-50%); background: white; border-radius: 10px; padding: 10px; width: 90%; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); display: flex; justify-content: space-between; opacity: 0; transition: opacity 0.5s ease; } .analytics-panel.visible { opacity: 1; } .analytics-item { text-align: center; padding: 5px 10px; } .analytics-item h4 { font-size: 12px; color: #555; margin-bottom: 5px; } .analytics-item p { font-size: 18px; font-weight: 700; color: #2e3192; } .analytics-item .trend { font-size: 11px; margin-top: 3px; } .analytics-item .trend.up { color: #4caf50; } .analytics-item .trend.down { color: #f44336; } .hover-area { position: absolute; width: 100%; height: 50px; bottom: 0; left: 0; z-index: 9; } .pattern-bg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0.05; z-index: 1; background-image: radial-gradient(circle, #4ecdc4 1px, transparent 1px); background-size: 20px 20px; } @media (max-width: 700px) { .container { width: 100%; height: 680px; padding: 15px; } h1 { font-size: 20px; } .description { font-size: 12px; } .node { width: 150px; padding: 12px; } .node.discovery { left: 42%; } .node.research { left: 15%; } .node.consideration { left: 65%; } .node.purchase { left: 42%; } .node.support { left: 15%; } .node.loyalty { left: 65%; } .node.advocacy { left: 42%; } .analytics-panel { flex-wrap: wrap; } .analytics-item { width: 50%; padding: 3px 5px; } .analytics-item p { font-size: 16px; } } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .pulse { animation: pulse 2s infinite; } </style> </head> <body> <div class="container"> <div class="pattern-bg"></div> <div class="header"> <h1>E-commerce Customer Journey</h1> <p class="description">Interactive visualization of the modern shopper's path to purchase. Click on any stage to reveal optimization strategies and relevant metrics.</p> </div> <div class="flowchart-container"> <!-- Discovery Node --> <div class="node discovery" data-id="discovery"> <div class="node-content"> <div class="icon">🔍</div> <h3>Discovery</h3> <p>Initial brand/product awareness</p> <div class="stat">68% via social media</div> </div> <div class="node-tip"> <span class="close-tip">×</span> <h4>Discovery Optimization</h4> <ul> <li>Leverage visual-first platforms like Instagram & TikTok</li> <li>Implement SEO for shopping intent keywords</li> <li>Use targeted ads with clear USPs</li> <li>Test multiple creative approaches monthly</li> </ul> </div> </div> <!-- Research Node --> <div class="node research" data-id="research"> <div class="node-content"> <div class="icon">📊</div> <h3>Research</h3> <p>Product comparison & evaluation</p> <div class="stat">4.2 sites visited avg.</div> </div> <div class="node-tip"> <span class="close-tip">×</span> <h4>Research Enhancement</h4> <ul> <li>Create detailed comparison guides with competitors</li> <li>Highlight verified customer reviews prominently</li> <li>Implement robust product filtering options</li> <li>Add video demonstrations for complex products</li> </ul> </div> </div> <!-- Consideration Node --> <div class="node consideration" data-id="consideration"> <div class="node-content"> <div class="icon">⚖️</div> <h3>Consideration</h3> <p>Cart addition & browsing</p> <div class="stat">71% cart abandonment</div> </div> <div class="node-tip"> <span class="close-tip">×</span> <h4>Abandonment Reduction</h4> <ul> <li>Implement exit-intent popups with incentives</li> <li>Send personalized cart reminder emails</li> <li>Show limited stock indicators where appropriate</li> <li>Display trust badges throughout checkout</li> </ul> </div> </div> <!-- Purchase Node --> <div class="node purchase" data-id="purchase"> <div class="node-content"> <div class="icon">💳</div> <h3>Purchase</h3> <p>Checkout & transaction</p> <div class="stat">3.5 min avg. checkout</div> </div> <div class="node-tip"> <span class="close-tip">×</span> <h4>Checkout Optimization</h4> <ul> <li>Reduce form fields to absolute minimum</li> <li>Add multiple payment options including BNPL</li> <li>Implement one-click purchase for returning customers</li> <li>Optimize mobile payment flow specifically</li> </ul> </div> </div> <!-- Support Node --> <div class="node support" data-id="support"> <div class="node-content"> <div class="icon">🛠️</div> <h3>Support</h3> <p>Post-purchase assistance</p> <div class="stat">14hr avg. response time</div> </div> <div class="node-tip"> <span class="close-tip">×</span> <h4>Support Enhancement</h4> <ul> <li>Implement AI chatbot for common queries</li> <li>Create detailed order tracking system</li> <li>Build comprehensive self-service knowledge base</li> <li>Offer proactive delivery updates via SMS</li> </ul> </div> </div> <!-- Loyalty Node --> <div class="node loyalty" data-id="loyalty"> <div class="node-content"> <div class="icon">🏆</div> <h3>Loyalty</h3> <p>Repeat purchases & retention</p> <div class="stat">27% customer retention</div> </div> <div class="node-tip"> <span class="close-tip">×</span> <h4>Retention Strategies</h4> <ul> <li>Implement tiered loyalty program with exclusive perks</li> <li>Send personalized product recommendations</li> <li>Create post-purchase content sequences</li> <li>Offer subscription options for repeat purchases</li> </ul> </div> </div> <!-- Advocacy Node --> <div class="node advocacy" data-id="advocacy"> <div class="node-content"> <div class="icon">📣</div> <h3>Advocacy</h3> <p>Referrals & social sharing</p> <div class="stat">13% become advocates</div> </div> <div class="node-tip"> <span class="close-tip">×</span> <h4>Advocacy Amplification</h4> <ul> <li>Implement dual-sided referral program</li> <li>Create shareable unboxing experiences</li> <li>Showcase customer content in marketing</li> <li>Build community through exclusive events</li> </ul> </div> </div> <!-- Connectors --> <div class="connector vertical" id="conn1"></div> <div class="connector horizontal" id="conn2"></div> <div class="connector horizontal" id="conn3"></div> <div class="connector vertical" id="conn4"></div> <div class="connector horizontal" id="conn5"></div> <div class="connector horizontal" id="conn6"></div> <div class="connector vertical" id="conn7"></div> </div> <div class="hover-area" id="hoverArea"></div> <div class="analytics-panel" id="analyticsPanel"> <div class="analytics-item"> <h4>Conv. Rate</h4> <p>3.2%</p> <div class="trend up">↑ 0.4%</div> </div> <div class="analytics-item"> <h4>AOV</h4> <p>$87</p> <div class="trend up">↑ $4</div> </div> <div class="analytics-item"> <h4>CLV</h4> <p>$312</p> <div class="trend up">↑ $28</div> </div> <div class="analytics-item"> <h4>Returns</h4> <p>5.8%</p> <div class="trend down">↓ 0.7%</div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Set up connectors positionConnectors(); // Add click listeners to nodes const nodes = document.querySelectorAll('.node'); nodes.forEach(node => { node.addEventListener('click', function() { // Close any other open tips document.querySelectorAll('.node.clicked').forEach(openNode => { if (openNode !== this) { openNode.classList.remove('clicked'); } }); this.classList.toggle('clicked'); updateConnectors(); }); // Close tip when close button is clicked const closeBtn = node.querySelector('.close-tip'); if (closeBtn) { closeBtn.addEventListener('click', function(e) { e.stopPropagation(); node.classList.remove('clicked'); updateConnectors(); }); } }); // Analytics panel reveal on hover const hoverArea = document.getElementById('hoverArea'); const analyticsPanel = document.getElementById('analyticsPanel'); hoverArea.addEventListener('mouseenter', function() { analyticsPanel.classList.add('visible'); }); document.querySelector('.flowchart-container').addEventListener('mouseleave', function() { if (!analyticsPanel.matches(':hover')) { analyticsPanel.classList.remove('visible'); } }); analyticsPanel.addEventListener('mouseleave', function() { analyticsPanel.classList.remove('visible'); }); // Add pulse animation to the discovery node to draw attention setTimeout(() => { const discoveryNode = document.querySelector('.node.discovery'); discoveryNode.classList.add('pulse'); // Remove pulse after a few seconds setTimeout(() => { discoveryNode.classList.remove('pulse'); }, 6000); }, 1000); // Handle window resize window.addEventListener('resize', positionConnectors); }); function positionConnectors() { // Discovery to Research const discovery = document.querySelector('.node.discovery'); const research = document.querySelector('.node.research'); const conn1 = document.getElementById('conn1'); const discoveryRect = discovery.getBoundingClientRect(); const researchRect = research.getBoundingClientRect(); conn1.style.height = ((researchRect.top - discoveryRect.bottom) + 10) + 'px'; conn1.style.left = (researchRect.left + researchRect.width / 2) + 'px'; conn1.style.top = (discoveryRect.bottom) + 'px'; // Discovery to Consideration const consideration = document.querySelector('.node.consideration'); const conn2 = document.getElementById('conn2'); const considerationRect = consideration.getBoundingClientRect(); conn2.style.width = ((considerationRect.left - discoveryRect.right) + 10) + 'px'; conn2.style.left = (discoveryRect.right) + 'px'; conn2.style.top = (discoveryRect.top + discoveryRect.height / 2) + 'px'; // Consideration to Research const conn3 = document.getElementById('conn3'); conn3.style.width = ((considerationRect.left - researchRect.right) - 10) + 'px'; conn3.style.left = (researchRect.right) + 'px'; conn3.style.top = (researchRect.top + researchRect.height / 2) + 'px'; // Research/Consideration to Purchase const purchase = document.querySelector('.node.purchase'); const conn4 = document.getElementById('conn4'); const purchaseRect = purchase.getBoundingClientRect(); conn4.style.height = ((purchaseRect.top - researchRect.bottom) - 10) + 'px'; conn4.style.left = (purchaseRect.left + purchaseRect.width / 2) + 'px'; conn4.style.top = (researchRect.bottom) + 'px'; // Purchase to Support const support = document.querySelector('.node.support'); const conn5 = document.getElementById('conn5'); const supportRect = support.getBoundingClientRect(); conn5.style.width = ((purchaseRect.left - supportRect.right) + 10) + 'px'; conn5.style.left = (supportRect.right) + 'px'; conn5.style.top = (supportRect.top + supportRect.height / 2) + 'px'; // Purchase to Loyalty const loyalty = document.querySelector('.node.loyalty'); const conn6 = document.getElementById('conn6'); const loyaltyRect = loyalty.getBoundingClientRect(); conn6.style.width = ((loyaltyRect.left - purchaseRect.right) - 10) + 'px'; conn6.style.left = (purchaseRect.right) + 'px'; conn6.style.top = (purchaseRect.top + purchaseRect.height / 2) + 'px'; // Support/Loyalty to Advocacy const advocacy = document.querySelector('.node.advocacy'); const conn7 = document.getElementById('conn7'); const advocacyRect = advocacy.getBoundingClientRect(); conn7.style.height = ((advocacyRect.top - supportRect.bottom) - 10) + 'px'; conn7.style.left = (advocacyRect.left + advocacyRect.width / 2) + 'px'; conn7.style.top = (supportRect.bottom) + 'px'; updateConnectors(); } function updateConnectors() { // Highlight connectors based on clicked nodes const connectors = document.querySelectorAll('.connector'); connectors.forEach(conn => conn.classList.remove('active')); const activeNodes = Array.from(document.querySelectorAll('.node.clicked')).map(node => node.dataset.id); // Logic to highlight active paths based on clicked nodes if (activeNodes.includes('discovery')) { document.getElementById('conn1').classList.add('active'); document.getElementById('conn2').classList.add('active'); } if (activeNodes.includes('research') || (activeNodes.includes('discovery') && activeNodes.includes('purchase'))) { document.getElementById('conn1').classList.add('active'); document.getElementById('conn4').classList.add('active'); } if (activeNodes.includes('consideration') || (activeNodes.includes('discovery') && activeNodes.includes('purchase'))) { document.getElementById('conn2').classList.add('active'); document.getElementById('conn4').classList.add('active'); } if (activeNodes.includes('research') && activeNodes.includes('consideration')) { document.getElementById('conn3').classList.add('active'); } if (activeNodes.includes('purchase')) { document.getElementById('conn5').classList.add('active'); document.getElementById('conn6').classList.add('active'); } if (activeNodes.includes('support') || (activeNodes.includes('purchase') && activeNodes.includes('advocacy'))) { document.getElementById('conn5').classList.add('active'); document.getElementById('conn7').classList.add('active'); } if (activeNodes.includes('loyalty') || (activeNodes.includes('purchase') && activeNodes.includes('advocacy'))) { document.getElementById('conn6').classList.add('active'); document.getElementById('conn7').classList.add('active'); } } </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>IT Infrastructure Flowchart</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #0f1620; color: #e9eef2; height: 100%; width: 100%; overflow: hidden; display: flex; flex-direction: column; } .container { width: 100%; height: 700px; max-width: 700px; margin: 0 auto; padding: 1rem; display: flex; flex-direction: column; } header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; border-bottom: 1px solid #2a3e52; padding-bottom: 0.5rem; position: relative; } h1 { font-size: 1.3rem; color: #4ecdc4; font-weight: 600; } .status { font-size: 0.7rem; padding: 0.3rem 0.6rem; background-color: #2a3e52; border-radius: 1rem; display: flex; align-items: center; } .status-indicator { width: 8px; height: 8px; border-radius: 50%; background-color: #4ecdc4; margin-right: 0.5rem; animation: pulse 2s infinite; } @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } } .controls { display: flex; margin-bottom: 1rem; gap: 0.5rem; } .button { background-color: #2a3e52; border: none; color: #e9eef2; padding: 0.4rem 0.8rem; border-radius: 0.3rem; font-size: 0.8rem; cursor: pointer; transition: all 0.2s ease; } .button:hover { background-color: #3d5575; } .button.active { background-color: #4ecdc4; color: #0f1620; } .search { flex: 1; display: flex; align-items: center; background-color: #2a3e52; border-radius: 0.3rem; padding: 0 0.5rem; } .search input { background: transparent; border: none; color: #e9eef2; padding: 0.4rem; font-size: 0.8rem; width: 100%; outline: none; } .search i { color: #8ca0b5; font-size: 0.8rem; } .flowchart-container { flex: 1; overflow: auto; position: relative; border-radius: 0.5rem; background-color: #1a2634; border: 1px solid #2a3e52; margin-bottom: 1rem; } .grid { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-image: linear-gradient(#2a3e5220 1px, transparent 1px), linear-gradient(90deg, #2a3e5220 1px, transparent 1px); background-size: 25px 25px; z-index: 1; } .flowchart { position: absolute; width: 1600px; height: 1000px; transform-origin: 0 0; } .node { position: absolute; background-color: #2a3e52; border-radius: 0.5rem; padding: 0.8rem; width: 120px; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); z-index: 3; } .node.active, .node:hover { background-color: #3d5575; box-shadow: 0 0 0 2px #4ecdc4, 0 4px 12px rgba(0, 0, 0, 0.3); } .node-title { font-size: 0.8rem; font-weight: 600; margin-bottom: 0.3rem; color: #4ecdc4; } .node-subtitle { font-size: 0.65rem; color: #b7c5d3; margin-bottom: 0.5rem; } .node-status { font-size: 0.65rem; display: flex; align-items: center; } .node-status span { width: 8px; height: 8px; border-radius: 50%; margin-right: 0.3rem; } .status-ok { background-color: #4ecdc4; } .status-warning { background-color: #ffcb47; } .status-critical { background-color: #ff6b6b; } .connection-container { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 2; } .connection { position: absolute; height: 2px; background-color: #4ecdc4; transform-origin: 0 0; pointer-events: none; opacity: 0.7; } .connection::after { content: ''; position: absolute; right: 0; top: -3px; width: 0; height: 0; border-top: 4px solid transparent; border-bottom: 4px solid transparent; border-left: 7px solid #4ecdc4; } .connection-data { position: absolute; animation: data-transfer 5s linear infinite; width: 4px; height: 4px; background-color: white; border-radius: 50%; z-index: 2; } @keyframes data-transfer { 0% { left: 0%; opacity: 0; } 5% { opacity: 1; } 95% { opacity: 1; } 100% { left: 100%; opacity: 0; } } .info-panel { background-color: #2a3e52; border-radius: 0.5rem; padding: 1rem; font-size: 0.8rem; position: relative; overflow: hidden; } .info-panel h2 { font-size: 1rem; margin-bottom: 0.5rem; color: #4ecdc4; } .metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; margin-top: 0.7rem; } .metric { background-color: #1a2634; border-radius: 0.3rem; padding: 0.5rem; } .metric-title { font-size: 0.65rem; color: #b7c5d3; margin-bottom: 0.3rem; } .metric-value { font-size: 1rem; font-weight: 600; } .cpu-high { color: #ff6b6b; } .memory-ok { color: #4ecdc4; } .traffic-medium { color: #ffcb47; } /* Circuit design pattern in bg */ .circuit-pattern { position: absolute; top: 0; right: 0; width: 50%; height: 100%; opacity: 0.06; background-image: radial-gradient(circle at 100% 100%, #4ecdc4 1px, transparent 1px), linear-gradient(to right, transparent 0%, #4ecdc4 100%); background-size: 20px 20px, 100% 100%; background-position: 0 0; pointer-events: none; } .zoom-controls { position: absolute; bottom: 1rem; right: 1rem; display: flex; gap: 0.5rem; z-index: 10; } .zoom-btn { width: 30px; height: 30px; border-radius: 50%; background-color: #2a3e52; color: #e9eef2; border: none; font-size: 1rem; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.2s ease; } .zoom-btn:hover { background-color: #4ecdc4; color: #0f1620; } /* Tooltip */ .tooltip { position: absolute; background-color: #0f1620; border: 1px solid #4ecdc4; border-radius: 0.3rem; padding: 0.5rem; font-size: 0.7rem; max-width: 200px; z-index: 20; pointer-events: none; opacity: 0; transition: opacity 0.2s ease; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); } .tooltip-title { color: #4ecdc4; font-weight: 600; margin-bottom: 0.3rem; } .tooltip p { margin-bottom: 0.3rem; color: #b7c5d3; } /* Media queries for responsiveness */ @media (max-width: 600px) { .metrics { grid-template-columns: repeat(2, 1fr); } h1 { font-size: 1.1rem; } .controls { flex-wrap: wrap; } .search { order: -1; width: 100%; margin-bottom: 0.5rem; } } </style> </head> <body> <div class="container"> <header> <h1>Enterprise Network Infrastructure</h1> <div class="status"> <div class="status-indicator"></div> <span>Monitoring Active</span> </div> </header> <div class="controls"> <div class="search"> <i>🔍</i> <input type="text" placeholder="Search nodes, IPs, services..." id="search"> </div> <button class="button active" data-view="network">Network View</button> <button class="button" data-view="server">Server View</button> <button class="button" data-view="security">Security View</button> </div> <div class="flowchart-container" id="flowchart-container"> <div class="grid"></div> <div class="flowchart" id="flowchart"> <!-- Nodes will be added by JavaScript --> </div> <div class="connection-container" id="connection-container"> <!-- Connections will be added by JavaScript --> </div> <div class="zoom-controls"> <button class="zoom-btn" id="zoom-out">-</button> <button class="zoom-btn" id="zoom-in">+</button> <button class="zoom-btn" id="zoom-reset">⟲</button> </div> </div> <div class="info-panel"> <div class="circuit-pattern"></div> <h2 id="selected-node-title">Primary Gateway Router</h2> <div id="selected-node-details">Select a node to view detailed information.</div> <div class="metrics"> <div class="metric"> <div class="metric-title">CPU Usage</div> <div class="metric-value cpu-high">87%</div> </div> <div class="metric"> <div class="metric-title">Memory</div> <div class="metric-value memory-ok">42%</div> </div> <div class="metric"> <div class="metric-title">Network Traffic</div> <div class="metric-value traffic-medium">62 Mbps</div> </div> </div> </div> <div class="tooltip" id="tooltip"> <div class="tooltip-title">Primary Gateway Router</div> <p>IP: 192.168.1.1</p> <p>Uptime: 143 days</p> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Node configuration data const nodes = [ { id: 'internet-gateway', title: 'Internet Gateway', subtitle: 'Cisco ASR 9000', status: 'ok', details: 'Primary internet connection point with 2x10Gbps redundant uplinks to ISP. BGP routing enabled with ASN 64512.', x: 200, y: 100, metrics: { cpu: '42%', memory: '38%', traffic: '1.8 Gbps', cpuClass: 'memory-ok', memoryClass: 'memory-ok', trafficClass: 'memory-ok' }, tooltip: { ip: '203.0.113.1', uptime: '289 days', firmware: 'IOS XR 7.3.2' } }, { id: 'firewall', title: 'Firewall Cluster', subtitle: 'Palo Alto PA-5220', status: 'ok', details: 'Active-passive HA firewall cluster with threat prevention, URL filtering, and application identification. Managing 240+ security policies.', x: 400, y: 100, metrics: { cpu: '36%', memory: '45%', traffic: '1.2 Gbps', cpuClass: 'memory-ok', memoryClass: 'memory-ok', trafficClass: 'memory-ok' }, tooltip: { ip: '10.0.0.1/2', uptime: '124 days', firmware: 'PAN-OS 10.1.4' } }, { id: 'core-switch', title: 'Core Switch', subtitle: 'Arista 7280R', status: 'ok', details: 'Layer 3 core switch with 48x25GbE + 6x100GbE ports. Running OSPF area 0 with 4ms convergence time.', x: 600, y: 100, metrics: { cpu: '29%', memory: '32%', traffic: '18.5 Gbps', cpuClass: 'memory-ok', memoryClass: 'memory-ok', trafficClass: 'memory-ok' }, tooltip: { ip: '10.0.1.1', uptime: '342 days', firmware: 'EOS 4.25.2F' } }, { id: 'dmz-switch', title: 'DMZ Switch', subtitle: 'Juniper EX4650', status: 'warning', details: 'Dedicated switch for DMZ segment with micro-segmentation. Port security and 802.1X authentication enforced.', x: 400, y: 250, metrics: { cpu: '56%', memory: '65%', traffic: '890 Mbps', cpuClass: 'traffic-medium', memoryClass: 'traffic-medium', trafficClass: 'memory-ok' }, tooltip: { ip: '10.1.0.1', uptime: '64 days', firmware: 'Junos 20.4R1' } }, { id: 'wlan-controller', title: 'WLAN Controller', subtitle: 'Aruba 7220', status: 'ok', details: 'Managing 112 access points across 4 buildings. Supporting 802.11ax with WPA3-Enterprise authentication.', x: 800, y: 250, metrics: { cpu: '32%', memory: '41%', traffic: '625 Mbps', cpuClass: 'memory-ok', memoryClass: 'memory-ok', trafficClass: 'memory-ok' }, tooltip: { ip: '10.0.3.10', uptime: '127 days', firmware: 'ArubaOS 8.7.1.0' } }, { id: 'web-server', title: 'Web Cluster', subtitle: 'Nginx + HAProxy', status: 'critical', details: 'Load-balanced web server farm with 8 Nginx instances behind HAProxy. TLS 1.3 with OCSP stapling enabled.', x: 400, y: 400, metrics: { cpu: '87%', memory: '62%', traffic: '325 Mbps', cpuClass: 'cpu-high', memoryClass: 'traffic-medium', trafficClass: 'memory-ok' }, tooltip: { ip: '10.2.0.10-17', uptime: '18 days', connections: '14,622 active' } }, { id: 'db-cluster', title: 'Database Cluster', subtitle: 'PostgreSQL 14', status: 'ok', details: 'Primary-secondary PostgreSQL cluster with streaming replication. 4TB of production data with 99.99% uptime SLA.', x: 600, y: 400, metrics: { cpu: '52%', memory: '78%', traffic: '210 Mbps', cpuClass: 'traffic-medium', memoryClass: 'traffic-medium', trafficClass: 'memory-ok' }, tooltip: { ip: '10.2.1.20-22', uptime: '154 days', backup: 'Last: 03:15 UTC' } }, { id: 'monitoring-system', title: 'Monitoring System', subtitle: 'Prometheus + Grafana', status: 'ok', details: 'Enterprise monitoring solution collecting 28,500 metrics from 342 targets with 15s resolution. Custom alerting rules.', x: 600, y: 550, metrics: { cpu: '48%', memory: '70%', traffic: '85 Mbps', cpuClass: 'memory-ok', memoryClass: 'traffic-medium', trafficClass: 'memory-ok' }, tooltip: { ip: '10.3.0.5', uptime: '97 days', alerts: '3 active warnings' } }, { id: 'backup-system', title: 'Backup System', subtitle: 'Veeam B&R', status: 'warning', details: 'Centralized backup solution with 120TB capacity. Daily incrementals with weekly synthetic fulls. Offsite replication to DR site.', x: 800, y: 400, metrics: { cpu: '23%', memory: '32%', traffic: '3.2 Gbps', cpuClass: 'memory-ok', memoryClass: 'memory-ok', trafficClass: 'traffic-medium' }, tooltip: { ip: '10.3.0.10', uptime: '45 days', storage: '87% used' } } ]; // Connection configuration const connections = [ { from: 'internet-gateway', to: 'firewall' }, { from: 'firewall', to: 'core-switch' }, { from: 'firewall', to: 'dmz-switch' }, { from: 'core-switch', to: 'wlan-controller' }, { from: 'core-switch', to: 'monitoring-system' }, { from: 'dmz-switch', to: 'web-server' }, { from: 'web-server', to: 'db-cluster' }, { from: 'db-cluster', to: 'monitoring-system' }, { from: 'core-switch', to: 'backup-system' }, { from: 'db-cluster', to: 'backup-system' } ]; const flowchartContainer = document.getElementById('flowchart-container'); const flowchart = document.getElementById('flowchart'); const connectionContainer = document.getElementById('connection-container'); const tooltip = document.getElementById('tooltip'); const selectedNodeTitle = document.getElementById('selected-node-title'); const selectedNodeDetails = document.getElementById('selected-node-details'); let scale = 0.7; let translateX = 0; let translateY = 0; let isDragging = false; let dragStartX = 0; let dragStartY = 0; let activeNodeId = null; // Create the nodes nodes.forEach(node => { const nodeElement = document.createElement('div'); nodeElement.className = `node ${node.id}`; nodeElement.id = node.id; nodeElement.innerHTML = ` <div class="node-title">${node.title}</div> <div class="node-subtitle">${node.subtitle}</div> <div class="node-status"> <span class="status-${node.status}"></span> ${node.status === 'ok' ? 'Operational' : node.status === 'warning' ? 'Warning' : 'Critical'} </div> `; nodeElement.style.left = `${node.x}px`; nodeElement.style.top = `${node.y}px`; // Add event listeners nodeElement.addEventListener('click', () => { // Remove active class from previously active node if (activeNodeId) { document.getElementById(activeNodeId).classList.remove('active'); } // Set this node as active nodeElement.classList.add('active'); activeNodeId = node.id; // Update info panel selectedNodeTitle.textContent = node.title; selectedNodeDetails.textContent = node.details; // Update metrics document.querySelector('.metrics').innerHTML = ` <div class="metric"> <div class="metric-title">CPU Usage</div> <div class="metric-value ${node.metrics.cpuClass}">${node.metrics.cpu}</div> </div> <div class="metric"> <div class="metric-title">Memory</div> <div class="metric-value ${node.metrics.memoryClass}">${node.metrics.memory}</div> </div> <div class="metric"> <div class="metric-title">Network Traffic</div> <div class="metric-value ${node.metrics.trafficClass}">${node.metrics.traffic}</div> </div> `; }); // Add tooltip functionality nodeElement.addEventListener('mouseenter', (e) => { const tooltipData = node.tooltip; tooltip.innerHTML = ` <div class="tooltip-title">${node.title}</div> ${Object.entries(tooltipData).map(([key, value]) => `<p>${key}: ${value}</p>`).join('')} `; tooltip.style.opacity = '1'; updateTooltipPosition(e); }); nodeElement.addEventListener('mousemove', updateTooltipPosition); nodeElement.addEventListener('mouseleave', () => { tooltip.style.opacity = '0'; }); flowchart.appendChild(nodeElement); }); // Create the connections connections.forEach((connection, index) => { drawConnection(connection.from, connection.to, index); }); // Add event listeners for dragging the flowchart flowchartContainer.addEventListener('mousedown', startDrag); flowchartContainer.addEventListener('touchstart', (e) => { if (e.touches.length === 1) { const touch = e.touches[0]; startDrag({ clientX: touch.clientX, clientY: touch.clientY }); } }, { passive: true }); document.addEventListener('mousemove', drag); document.addEventListener('touchmove', (e) => { if (e.touches.length === 1) { e.preventDefault(); const touch = e.touches[0]; drag({ clientX: touch.clientX, clientY: touch.clientY }); } }, { passive: false }); document.addEventListener('mouseup', endDrag); document.addEventListener('touchend', endDrag); // Zoom controls document.getElementById('zoom-in').addEventListener('click', () => { scale += 0.1; updateTransform(); }); document.getElementById('zoom-out').addEventListener('click', () => { if (scale > 0.2) { scale -= 0.1; updateTransform(); } }); document.getElementById('zoom-reset').addEventListener('click', () => { scale = 0.7; translateX = 0; translateY = 0; updateTransform(); }); // Search functionality document.getElementById('search').addEventListener('input', (e) => { const searchTerm = e.target.value.toLowerCase(); nodes.forEach(node => { const element = document.getElementById(node.id); if ( node.title.toLowerCase().includes(searchTerm) || node.subtitle.toLowerCase().includes(searchTerm) || (node.tooltip && Object.values(node.tooltip).some(value => value.toString().toLowerCase().includes(searchTerm) )) ) { element.style.opacity = '1'; element.style.border = searchTerm ? '2px solid #ff6b6b' : '2px solid transparent'; } else { element.style.opacity = searchTerm ? '0.4' : '1'; element.style.border = '2px solid transparent'; } }); }); // View toggle document.querySelectorAll('.button[data-view]').forEach(button => { button.addEventListener('click', () => { document.querySelectorAll('.button[data-view]').forEach(b => b.classList.remove('active')); button.classList.add('active'); const view = button.getAttribute('data-view'); toggleView(view); }); }); // Initial transform updateTransform(); // Trigger click on first node to show its details setTimeout(() => { document.getElementById(nodes[0].id).click(); }, 500); // Functions function drawConnection(fromNodeId, toNodeId, index) { const fromNode = document.getElementById(fromNodeId); const toNode = document.getElementById(toNodeId); if (!fromNode || !toNode) return; const fromRect = fromNode.getBoundingClientRect(); const toRect = toNode.getBoundingClientRect(); // Get positions relative to flowchart container const fromX = parseInt(fromNode.style.left) + fromNode.offsetWidth / 2; const fromY = parseInt(fromNode.style.top) + fromNode.offsetHeight / 2; const toX = parseInt(toNode.style.left) + toNode.offsetWidth / 2; const toY = parseInt(toNode.style.top) + toNode.offsetHeight / 2; // Calculate line length and angle const dx = toX - fromX; const dy = toY - fromY; const length = Math.sqrt(dx * dx + dy * dy); const angle = Math.atan2(dy, dx) * 180 / Math.PI; // Create the connection line const line = document.createElement('div'); line.className = 'connection'; line.style.width = `${length}px`; line.style.left = `${fromX}px`; line.style.top = `${fromY}px`; line.style.transform = `rotate(${angle}deg)`; // Add data packets for animation for (let i = 0; i < 3; i++) { const dataPacket = document.createElement('div'); dataPacket.className = 'connection-data'; dataPacket.style.animationDelay = `${i * 1.5}s`; line.appendChild(dataPacket); } connectionContainer.appendChild(line); } function updateTooltipPosition(e) { const x = e.clientX; const y = e.clientY; const tooltipWidth = tooltip.offsetWidth; const tooltipHeight = tooltip.offsetHeight; // Position the tooltip while ensuring it stays within bounds let left = x + 15; let top = y + 15; // Adjust if too close to right edge if (left + tooltipWidth > window.innerWidth) { left = x - tooltipWidth - 15; } // Adjust if too close to bottom edge if (top + tooltipHeight > window.innerHeight) { top = y - tooltipHeight - 15; } tooltip.style.left = `${left}px`; tooltip.style.top = `${top}px`; } function startDrag(e) { if (e.target.closest('.node') || e.target.closest('.zoom-btn')) { return; } isDragging = true; dragStartX = e.clientX - translateX; dragStartY = e.clientY - translateY; flowchartContainer.style.cursor = 'grabbing'; } function drag(e) { if (!isDragging) return; translateX = e.clientX - dragStartX; translateY = e.clientY - dragStartY; updateTransform(); } function endDrag() { isDragging = false; flowchartContainer.style.cursor = 'grab'; } function updateTransform() { flowchart.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scale})`; } function toggleView(view) { const allNodes = document.querySelectorAll('.node'); const allConnections = document.querySelectorAll('.connection'); switch (view) { case 'network': allNodes.forEach(node => node.style.display = 'block'); allConnections.forEach(conn => conn.style.display = 'block'); break; case 'server': allNodes.forEach(node => { if (node.id.includes('server') || node.id.includes('db') || node.id.includes('backup')) { node.style.display = 'block'; } else { node.style.display = 'none'; } }); // Hide connections not related to visible nodes allConnections.forEach((conn, i) => { const connection = connections[i]; if (!connection) return; const fromVisible = document.getElementById(connection.from).style.display !== 'none'; const toVisible = document.getElementById(connection.to).style.display !== 'none'; conn.style.display = (fromVisible && toVisible) ? 'block' : 'none'; }); break; case 'security': allNodes.forEach(node => { if (node.id.includes('firewall') || node.id.includes('gateway') || node.id.includes('dmz')) { node.style.display = 'block'; } else { node.style.display = 'none'; } }); // Hide connections not related to visible nodes allConnections.forEach((conn, i) => { const connection = connections[i]; if (!connection) return; const fromVisible = document.getElementById(connection.from).style.display !== 'none'; const toVisible = document.getElementById(connection.to).style.display !== 'none'; conn.style.display = (fromVisible && toVisible) ? 'block' : 'none'; }); break; } } // Simulate real-time updates setInterval(() => { // Randomly update one node's status const randomNodeIndex = Math.floor(Math.random() * nodes.length); const nodeToUpdate = nodes[randomNodeIndex]; const nodeElement = document.getElementById(nodeToUpdate.id); // Only update if not currently selected (to avoid confusion) if (nodeToUpdate.id !== activeNodeId) { const statusTypes = ['ok', 'warning', 'critical']; const randomStatus = statusTypes[Math.floor(Math.random() * statusTypes.length)]; // Update status in DOM const statusElement = nodeElement.querySelector('.node-status'); statusElement.innerHTML = ` <span class="status-${randomStatus}"></span> ${randomStatus === 'ok' ? 'Operational' : randomStatus === 'warning' ? 'Warning' : 'Critical'} `; // Update in data model nodeToUpdate.status = randomStatus; } }, 15000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Customer Service Workflow</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f7f9fc; height: 100vh; display: flex; justify-content: center; align-items: center; overflow: hidden; color: #2c3e50; } .container { width: 700px; height: 700px; position: relative; overflow: hidden; } .workflow-container { width: 100%; height: 100%; padding: 20px; position: relative; overflow: auto; scrollbar-width: thin; scrollbar-color: #4a90e2 #f0f4f8; } .workflow-container::-webkit-scrollbar { width: 8px; } .workflow-container::-webkit-scrollbar-track { background: #f0f4f8; border-radius: 10px; } .workflow-container::-webkit-scrollbar-thumb { background-color: #4a90e2; border-radius: 10px; } .header { text-align: center; margin-bottom: 25px; position: sticky; top: 0; background-color: rgba(247, 249, 252, 0.95); padding: 15px 0; z-index: 10; border-bottom: 1px solid #e1e8ed; } h1 { color: #3498db; font-size: 2rem; margin-bottom: 10px; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); } .subtitle { color: #7f8c8d; font-size: 0.9rem; } .workflow { display: flex; flex-direction: column; align-items: center; position: relative; padding-bottom: 50px; } .node { width: 200px; padding: 15px; margin: 15px 0; border-radius: 10px; text-align: center; position: relative; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); z-index: 2; } .node:hover { transform: translateY(-5px); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2); } .node.start { background: linear-gradient(135deg, #3498db, #2980b9); color: white; } .node.decision { background: linear-gradient(135deg, #e67e22, #d35400); color: white; clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); width: 180px; height: 180px; display: flex; justify-content: center; align-items: center; padding: 25px; } .node.process { background: linear-gradient(135deg, #3498db, #2c3e50); color: white; } .node.end { background: linear-gradient(135deg, #2ecc71, #27ae60); color: white; } .connector { height: 30px; width: 3px; background-color: #95a5a6; position: relative; } .connector::after { content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 8px solid #95a5a6; } .branches { display: flex; justify-content: center; width: 100%; position: relative; } .branch { display: flex; flex-direction: column; align-items: center; margin: 0 25px; position: relative; } .branch-connector { position: absolute; background-color: #95a5a6; } .branch-connector.horizontal { height: 3px; width: 100%; top: -15px; } .branch-connector.vertical { height: 30px; width: 3px; top: -45px; left: 50%; transform: translateX(-50%); } .info-panel { position: fixed; width: 300px; background: white; border-radius: 10px; padding: 20px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); transform: translateY(20px); opacity: 0; visibility: hidden; transition: all 0.3s ease; z-index: 100; max-height: 400px; overflow-y: auto; } .info-panel.active { transform: translateY(0); opacity: 1; visibility: visible; } .info-panel h3 { margin-bottom: 10px; color: #3498db; border-bottom: 2px solid #f0f4f8; padding-bottom: 10px; } .info-panel .close-btn { position: absolute; top: 15px; right: 15px; cursor: pointer; font-size: 1rem; color: #95a5a6; transition: color 0.3s ease; } .info-panel .close-btn:hover { color: #e74c3c; } .info-panel p { margin-bottom: 15px; font-size: 0.9rem; line-height: 1.5; } .info-panel ul { margin-left: 20px; margin-bottom: 15px; } .info-panel li { margin-bottom: 8px; font-size: 0.9rem; } .key-points { background-color: #f0f7fa; padding: 12px; border-radius: 6px; margin-top: 10px; } .key-points h4 { color: #3498db; margin-bottom: 8px; font-size: 0.95rem; } .pulse { animation: pulse 2s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(52, 152, 219, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(52, 152, 219, 0); } 100% { box-shadow: 0 0 0 0 rgba(52, 152, 219, 0); } } .branch-label { font-size: 0.8rem; color: #7f8c8d; margin: 5px 0; font-weight: bold; } .watermark { position: absolute; bottom: 20px; right: 20px; opacity: 0.7; font-size: 0.8rem; color: #95a5a6; pointer-events: none; } .tooltip { position: absolute; background: rgba(44, 62, 80, 0.95); color: white; padding: 5px 10px; border-radius: 5px; font-size: 0.8rem; pointer-events: none; opacity: 0; transition: opacity 0.3s ease; z-index: 1000; } @media (max-width: 700px) { .workflow-container { padding: 15px; } h1 { font-size: 1.5rem; } .node { width: 180px; padding: 12px; font-size: 0.9rem; } .node.decision { width: 160px; height: 160px; padding: 20px; } .branch { margin: 0 15px; } .info-panel { width: 250px; max-height: 350px; } } .pattern-bg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: radial-gradient(circle at 10px 10px, rgba(52, 152, 219, 0.05) 2px, transparent 0); background-size: 20px 20px; pointer-events: none; z-index: 0; } </style> </head> <body> <div class="container"> <div class="workflow-container"> <div class="pattern-bg"></div> <div class="header"> <h1>Call Center Resolution Workflow</h1> <p class="subtitle">Interactive guide for efficient customer service handling</p> </div> <div class="workflow"> <div class="node start pulse" data-info="call-start"> Call Received </div> <div class="connector"></div> <div class="node process" data-info="identification"> Customer Identification </div> <div class="connector"></div> <div class="node process" data-info="issue-capture"> Issue Capture & Classification </div> <div class="connector"></div> <div class="node decision" data-info="standard-issue"> Is this a<br>standard issue? </div> <div class="branches"> <div class="branch"> <div class="branch-connector horizontal"></div> <div class="branch-connector vertical"></div> <div class="branch-label">YES</div> <div class="node process" data-info="sop"> Follow Standard Operating Procedure </div> <div class="connector"></div> <div class="node process" data-info="resolution"> Provide Solution </div> </div> <div class="branch"> <div class="branch-connector horizontal"></div> <div class="branch-connector vertical"></div> <div class="branch-label">NO</div> <div class="node process" data-info="escalation"> Escalate to Specialized Team </div> <div class="connector"></div> <div class="node decision" data-info="resolution-available"> Solution<br>Available? </div> <div class="branches"> <div class="branch"> <div class="branch-connector horizontal"></div> <div class="branch-connector vertical"></div> <div class="branch-label">YES</div> <div class="node process" data-info="specialist-solution"> Provide Specialist Solution </div> </div> <div class="branch"> <div class="branch-connector horizontal"></div> <div class="branch-connector vertical"></div> <div class="branch-label">NO</div> <div class="node process" data-info="ticket-creation"> Create Service Ticket </div> </div> </div> </div> </div> <div class="connector" style="margin-top: 50px;"></div> <div class="node process" data-info="satisfaction"> Customer Satisfaction Verification </div> <div class="connector"></div> <div class="node end" data-info="call-end"> Call Conclusion </div> </div> <div class="watermark">Designed for RapidResponse™ Call Center Teams</div> </div> </div> <div class="info-panel" id="infoPanel"> <span class="close-btn">×</span> <h3 id="infoPanelTitle">Node Info</h3> <div id="infoPanelContent"></div> </div> <div class="tooltip" id="tooltip"></div> <script> document.addEventListener('DOMContentLoaded', function() { const infoPanel = document.getElementById('infoPanel'); const infoPanelTitle = document.getElementById('infoPanelTitle'); const infoPanelContent = document.getElementById('infoPanelContent'); const closeBtn = document.querySelector('.close-btn'); const tooltip = document.getElementById('tooltip'); // Info for each node const nodeInfo = { 'call-start': { title: 'Call Received', content: ` <p>The initial point of contact where a customer reaches the call center. Within the first 10 seconds, establish a professional and helpful tone.</p> <div class="key-points"> <h4>Key Actions:</h4> <ul> <li>Answer with standard greeting: "Thank you for calling [Company]. This is [Name], how may I assist you today?"</li> <li>Note the timestamp for call metrics (avg. response time: <20 sec)</li> <li>Verify call quality and connection before proceeding</li> </ul> </div> ` }, 'identification': { title: 'Customer Identification', content: ` <p>Authenticate the customer to access their account information securely while maintaining GDPR/privacy compliance.</p> <div class="key-points"> <h4>Verification Methods:</h4> <ul> <li>Primary: Account number + last 4 digits of registered phone</li> <li>Secondary: Email address + one security question</li> <li>Escalated: PIN verification via SMS (if standard methods fail)</li> </ul> <h4>System Actions:</h4> <ul> <li>Pull up customer's interaction history from CRM</li> <li>Note account status flags (VIP, recent issues, etc.)</li> </ul> </div> ` }, 'issue-capture': { title: 'Issue Capture & Classification', content: ` <p>Accurately document the customer's concern and categorize it for appropriate routing and resolution tracking.</p> <div class="key-points"> <h4>Primary Categories:</h4> <ul> <li>Technical Support (T1-T4 severity levels)</li> <li>Billing Inquiries (payment, disputes, plans)</li> <li>Account Management (changes, upgrades, cancellations)</li> <li>Product Information (features, compatibility)</li> <li>Complaints (service, staff, policies)</li> </ul> <h4>Active Listening Techniques:</h4> <ul> <li>Paraphrase to confirm understanding: "So what I'm hearing is..."</li> <li>Document key details in the ticket within the QuickNote system</li> </ul> </div> ` }, 'standard-issue': { title: 'Standard Issue Assessment', content: ` <p>Determine if the issue falls within the scope of common problems with documented solutions or requires specialized handling.</p> <div class="key-points"> <h4>Standard Issues Include:</h4> <ul> <li>Password resets and account access problems</li> <li>Basic technical troubleshooting (Tier 1)</li> <li>Order status inquiries</li> <li>Common billing questions</li> <li>Standard product information requests</li> </ul> <h4>Non-Standard Issues Include:</h4> <ul> <li>Complex technical issues (Tier 2+)</li> <li>Billing disputes over $250</li> <li>Legal or compliance matters</li> <li>Multiple issue tickets with repeated failures</li> <li>Any issue flagged as "critical" in the system</li> </ul> </div> ` }, 'sop': { title: 'Standard Operating Procedure', content: ` <p>Follow established troubleshooting paths and solution scripts for known issues to ensure consistency and efficiency.</p> <div class="key-points"> <h4>SOP Guidelines:</h4> <ul> <li>Access relevant knowledge base article using SmartSearch</li> <li>Follow step-by-step resolution protocol in the order specified</li> <li>Use prescribed language for technical instructions</li> <li>Document each attempted solution in real-time</li> </ul> <h4>Efficiency Metrics:</h4> <ul> <li>Target resolution time: 3-8 minutes (issue dependent)</li> <li>No more than 2 holds per standard call</li> <li>Hold time limit: 60 seconds without check-in</li> </ul> </div> ` }, 'resolution': { title: 'Provide Solution', content: ` <p>Clearly communicate the resolution to the customer, ensuring they understand and can implement any required actions.</p> <div class="key-points"> <h4>Solution Delivery Best Practices:</h4> <ul> <li>Use clear, jargon-free language appropriate to customer's technical level</li> <li>Break complex solutions into numbered steps</li> <li>Confirm customer's understanding after each key point</li> <li>Offer to email written instructions for multi-step solutions</li> </ul> <h4>Verification:</h4> <ul> <li>Guide customer to test the solution while still on the call</li> <li>Ask: "Has this fully resolved your concern today?"</li> <li>Document exact resolution in the CRM for future reference</li> </ul> </div> ` }, 'escalation': { title: 'Escalate to Specialized Team', content: ` <p>Transfer the issue to the appropriate specialized department when it requires expertise beyond first-level support capabilities.</p> <div class="key-points"> <h4>Escalation Protocol:</h4> <ul> <li>Inform customer of escalation need and expected process</li> <li>Complete the E-Form with all relevant details before transfer</li> <li>Use warm transfer when available (introduces customer to specialist)</li> <li>Provide estimated response time based on current queue status</li> </ul> <h4>Specialized Teams:</h4> <ul> <li>Technical Support Tier 2/3 (ext. 4230)</li> <li>Billing Resolution Unit (ext. 5110)</li> <li>Account Security Team (ext. 4008)</li> <li>Product Specialists (ext. varies by product line)</li> <li>Customer Retention (ext. 5502)</li> </ul> </div> ` }, 'resolution-available': { title: 'Solution Availability Check', content: ` <p>Determine if the specialized team can provide an immediate resolution or if further investigation is required.</p> <div class="key-points"> <h4>Immediate Solutions Criteria:</h4> <ul> <li>Issue is documented in extended knowledge base</li> <li>Resolution can be implemented during the current call</li> <li>No system limitations preventing immediate action</li> <li>No required approvals from unavailable personnel</li> </ul> <h4>Solution Unavailable When:</h4> <ul> <li>Problem requires development team intervention</li> <li>Issue involves third-party vendor resolution</li> <li>Required action is outside business hours for essential team</li> <li>Complex account adjustments exceeding specialist authority</li> </ul> </div> ` }, 'specialist-solution': { title: 'Provide Specialist Solution', content: ` <p>Deliver expert-level resolution for complex issues that required specialized knowledge or system access.</p> <div class="key-points"> <h4>Specialist Protocols:</h4> <ul> <li>Access elevated system permissions as required</li> <li>Apply specialized troubleshooting methods</li> <li>Document solution in detail for knowledge base update</li> <li>Educate customer on preventing similar issues</li> </ul> <h4>Quality Assurance:</h4> <ul> <li>Test solution thoroughly before confirming resolution</li> <li>Update ticket with specialist action codes</li> <li>Flag recurring issues for product improvement team</li> </ul> </div> ` }, 'ticket-creation': { title: 'Create Service Ticket', content: ` <p>Generate a formal tracking record for issues requiring extended research, development work, or follow-up from offline teams.</p> <div class="key-points"> <h4>Ticket Requirements:</h4> <ul> <li>Complete ServiceDesk case with severity classification</li> <li>All troubleshooting steps already attempted</li> <li>Detailed customer impact statement</li> <li>Reproduction steps (if applicable)</li> <li>Customer's preferred contact method for updates</li> </ul> <h4>Customer Communication:</h4> <ul> <li>Provide ticket number and explain tracking process</li> <li>Set realistic timeframe expectations based on severity</li> <li>Explain next steps and when they can expect updates</li> <li>Offer workarounds when available</li> </ul> </div> ` }, 'satisfaction': { title: 'Customer Satisfaction Verification', content: ` <p>Confirm the customer's satisfaction with the resolution and overall service experience before concluding the interaction.</p> <div class="key-points"> <h4>Satisfaction Check Protocol:</h4> <ul> <li>Ask directly: "Have we fully resolved your concerns today?"</li> <li>Offer additional assistance: "Is there anything else you need help with?"</li> <li>Invite feedback: "How was your experience with our support today?"</li> <li>Note satisfaction level in call record (1-5 scale)</li> </ul> <h4>Recovery Actions (If Dissatisfied):</h4> <ul> <li>Acknowledge concerns empathetically</li> <li>Offer appropriate remediation options</li> <li>Escalate to supervisor if satisfaction cannot be achieved</li> <li>Flag for follow-up quality check within 24 hours</li> </ul> </div> ` }, 'call-end': { title: 'Call Conclusion', content: ` <p>Properly close the interaction with appropriate documentation and final customer communication.</p> <div class="key-points"> <h4>Conclusion Checklist:</h4> <ul> <li>Summarize the issue and resolution</li> <li>Confirm no additional questions remain</li> <li>Provide case reference number for future inquiries</li> <li>Inform about the automated satisfaction survey (if applicable)</li> <li>End with approved closing statement: "Thank you for contacting [Company]. We appreciate your business."</li> </ul> <h4>Post-Call Actions:</h4> <ul> <li>Complete call documentation within 45 seconds</li> <li>Apply correct resolution and category codes</li> <li>Send promised follow-up materials</li> <li>Set follow-up reminders if promised</li> </ul> </div> ` } }; // Add click event to nodes document.querySelectorAll('.node').forEach(node => { node.addEventListener('click', function(e) { const infoKey = this.getAttribute('data-info'); if (nodeInfo[infoKey]) { infoPanelTitle.textContent = nodeInfo[infoKey].title; infoPanelContent.innerHTML = nodeInfo[infoKey].content; // Position the panel const rect = this.getBoundingClientRect(); const containerRect = document.querySelector('.container').getBoundingClientRect(); const panelWidth = 300; let leftPos = rect.left + rect.width / 2 - panelWidth / 2; // Keep panel within container bounds if (leftPos < containerRect.left + 10) { leftPos = containerRect.left + 10; } else if (leftPos + panelWidth > containerRect.right - 10) { leftPos = containerRect.right - panelWidth - 10; } infoPanel.style.left = `${leftPos}px`; // If node is in bottom half, show panel above if (rect.top > window.innerHeight / 2) { infoPanel.style.top = 'auto'; infoPanel.style.bottom = `${window.innerHeight - rect.top + 10}px`; } else { infoPanel.style.top = `${rect.bottom + 10}px`; infoPanel.style.bottom = 'auto'; } infoPanel.classList.add('active'); e.stopPropagation(); } }); // Add hover tooltip node.addEventListener('mouseenter', function() { const infoKey = this.getAttribute('data-info'); if (nodeInfo[infoKey]) { tooltip.textContent = nodeInfo[infoKey].title; tooltip.style.opacity = '1'; const rect = this.getBoundingClientRect(); tooltip.style.left = `${rect.left + rect.width / 2 - tooltip.offsetWidth / 2}px`; tooltip.style.top = `${rect.top - tooltip.offsetHeight - 10}px`; } }); node.addEventListener('mousemove', function(e) { // Update tooltip position on mouse move for a smoother experience const infoKey = this.getAttribute('data-info'); if (nodeInfo[infoKey] && tooltip.style.opacity === '1') { tooltip.style.left = `${e.clientX - tooltip.offsetWidth / 2}px`; tooltip.style.top = `${e.clientY - tooltip.offsetHeight - 15}px`; } }); node.addEventListener('mouseleave', function() { tooltip.style.opacity = '0'; }); }); // Close panel when clicking the close button closeBtn.addEventListener('click', function() { infoPanel.classList.remove('active'); }); // Close panel when clicking outside document.addEventListener('click', function(e) { if (!infoPanel.contains(e.target) && !e.target.classList.contains('node')) { infoPanel.classList.remove('active'); } }); // Fancy animation for connector lines const connectors = document.querySelectorAll('.connector'); connectors.forEach(connector => { setTimeout(() => { connector.style.transition = 'height 0.8s ease'; connector.style.height = '40px'; }, 500); }); // Make workflow scrollable with mouse wheel const workflow = document.querySelector('.workflow-container'); workflow.addEventListener('wheel', function(e) { workflow.scrollTop += e.deltaY; }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Manufacturing Process Flowchart</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Roboto Mono', monospace; } body { background-color: #1e1e1e; color: #d4d4d4; display: flex; justify-content: center; align-items: center; min-height: 700px; width: 100%; overflow-x: hidden; padding: 20px; background-image: linear-gradient(rgba(38, 38, 38, 0.7) 1px, transparent 1px), linear-gradient(90deg, rgba(38, 38, 38, 0.7) 1px, transparent 1px); background-size: 20px 20px; } .container { width: 100%; max-width: 680px; height: 660px; background-color: #2a2a2a; border-radius: 8px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); padding: 20px; position: relative; overflow: hidden; border: 1px solid #444; } .header { text-align: center; margin-bottom: 20px; border-bottom: 2px solid #555; padding-bottom: 15px; position: relative; } .header h1 { font-size: 24px; font-weight: 700; color: #ff8c00; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 5px; } .header p { font-size: 14px; color: #aaa; } .blueprint-indicator { position: absolute; top: 10px; right: 10px; display: flex; align-items: center; gap: 5px; font-size: 12px; color: #aaa; } .status-light { width: 10px; height: 10px; border-radius: 50%; background-color: #4CAF50; animation: blink 2s infinite; } @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } .flowchart { display: flex; flex-direction: column; gap: 20px; height: calc(100% - 80px); overflow-y: auto; scrollbar-width: thin; scrollbar-color: #555 #2a2a2a; padding-right: 10px; } .flowchart::-webkit-scrollbar { width: 8px; } .flowchart::-webkit-scrollbar-track { background: #2a2a2a; } .flowchart::-webkit-scrollbar-thumb { background-color: #555; border-radius: 10px; } .step { background-color: #333; border-radius: 6px; padding: 15px; position: relative; border-left: 4px solid; transition: transform 0.3s ease, box-shadow 0.3s ease; cursor: pointer; opacity: 0; transform: translateX(-20px); animation: fadeIn 0.5s forwards; display: flex; flex-direction: column; } .step:hover { transform: translateY(-5px); box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2); } .step.raw-materials { border-left-color: #8bc34a; } .step.preparation { border-left-color: #03a9f4; } .step.manufacturing { border-left-color: #ff9800; } .step.quality-control { border-left-color: #e91e63; } .step.packaging { border-left-color: #9c27b0; } .step.distribution { border-left-color: #607d8b; } .step-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .step-number { width: 25px; height: 25px; border-radius: 50%; background-color: #444; display: flex; justify-content: center; align-items: center; font-size: 12px; font-weight: bold; } .raw-materials .step-number { background-color: #8bc34a; color: #333; } .preparation .step-number { background-color: #03a9f4; color: #333; } .manufacturing .step-number { background-color: #ff9800; color: #333; } .quality-control .step-number { background-color: #e91e63; color: #fff; } .packaging .step-number { background-color: #9c27b0; color: #fff; } .distribution .step-number { background-color: #607d8b; color: #fff; } .step-title { font-size: 16px; font-weight: bold; color: #ffffff; flex-grow: 1; margin-left: 10px; text-transform: uppercase; } .time-estimate { font-size: 12px; background-color: #444; padding: 3px 8px; border-radius: 4px; display: flex; align-items: center; gap: 4px; } .time-estimate i { font-size: 14px; } .step-content { display: flex; flex-direction: column; gap: 10px; max-height: 0; overflow: hidden; transition: max-height 0.4s ease; } .step.active .step-content { max-height: 300px; } .description { font-size: 14px; line-height: 1.4; color: #bbb; } .safety-warning { background-color: rgba(255, 87, 34, 0.1); border-left: 3px solid #ff5722; padding: 8px 12px; font-size: 13px; color: #ff9e80; display: flex; align-items: center; gap: 8px; } .safety-warning i { color: #ff5722; } .connector { height: 20px; width: 2px; background-color: #555; margin: -10px auto; position: relative; z-index: 1; } .connector::before { content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 6px solid #555; } @keyframes fadeIn { to { opacity: 1; transform: translateX(0); } } .legend { display: flex; justify-content: center; gap: 12px; flex-wrap: wrap; margin-top: 20px; padding-top: 15px; border-top: 1px solid #444; } .legend-item { display: flex; align-items: center; gap: 5px; font-size: 11px; color: #aaa; } .legend-color { width: 12px; height: 12px; border-radius: 3px; } .color-raw { background-color: #8bc34a; } .color-prep { background-color: #03a9f4; } .color-manuf { background-color: #ff9800; } .color-qc { background-color: #e91e63; } .color-pack { background-color: #9c27b0; } .color-dist { background-color: #607d8b; } .watermark { position: absolute; bottom: 10px; right: 15px; font-size: 12px; color: #555; display: flex; align-items: center; gap: 5px; } .watermark i { font-size: 14px; } @media (max-width: 500px) { .header h1 { font-size: 20px; } .step { padding: 12px; } .step-title { font-size: 14px; } .legend { gap: 8px; } .legend-item { font-size: 10px; } } </style> <link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500;700&display=swap" rel="stylesheet"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> </head> <body> <div class="container"> <div class="header"> <h1>Precision Manufacturing Process</h1> <p>CNC Machined Aluminum Components - Production Sequence</p> <div class="blueprint-indicator"> <div class="status-light"></div> <span>LIVE MONITORING</span> </div> </div> <div class="flowchart"> <div class="step raw-materials" data-step="1"> <div class="step-header"> <div class="step-number">1</div> <div class="step-title">Raw Materials Intake</div> <div class="time-estimate"><i class="fas fa-clock"></i> 45min</div> </div> <div class="step-content"> <div class="description"> Inbound 6061-T6 aluminum stock verification and quality assessment. Batches are logged into ERP system with material certificates and alloy composition verified against specifications. </div> <div class="safety-warning"> <i class="fas fa-exclamation-triangle"></i> Materials handling requires proper PPE including cut-resistant gloves and eye protection. </div> </div> </div> <div class="connector"></div> <div class="step preparation" data-step="2"> <div class="step-header"> <div class="step-number">2</div> <div class="step-title">Material Preparation</div> <div class="time-estimate"><i class="fas fa-clock"></i> 2.5hrs</div> </div> <div class="step-content"> <div class="description"> Raw stock cutting to specified dimensions (+0.5mm tolerance) on industrial band saws. Material is degreased and surface-prepped for machining operations. Each blank is marked with batch number and orientation indicators. </div> <div class="safety-warning"> <i class="fas fa-exclamation-triangle"></i> Cutting operations require machine guards in place and hearing protection. Coolant mist may be present. </div> </div> </div> <div class="connector"></div> <div class="step manufacturing" data-step="3"> <div class="step-header"> <div class="step-number">3</div> <div class="step-title">CNC Machining Operations</div> <div class="time-estimate"><i class="fas fa-clock"></i> 4.2hrs</div> </div> <div class="step-content"> <div class="description"> Multi-axis CNC machining program execution in two phases: (1) Roughing operations with high material removal rate (2) Finishing passes with specialized tooling to achieve ±0.025mm tolerance and 32 Ra μin surface finish. Tool paths verified through digital twin simulation. </div> <div class="safety-warning"> <i class="fas fa-exclamation-triangle"></i> Full machine enclosures must be secured before operation. Emergency stop procedures posted at each workstation. </div> </div> </div> <div class="connector"></div> <div class="step quality-control" data-step="4"> <div class="step-header"> <div class="step-number">4</div> <div class="step-title">Quality Assurance</div> <div class="time-estimate"><i class="fas fa-clock"></i> 1.8hrs</div> </div> <div class="step-content"> <div class="description"> Parts undergo CMM dimensional verification per drawing requirements. Critical features are measured at 100% inspection rate, other characteristics at AQL level II. Surface finish verification using profilometer. Material hardness tested on sample basis. </div> </div> </div> <div class="connector"></div> <div class="step packaging" data-step="5"> <div class="step-header"> <div class="step-number">5</div> <div class="step-title">Finishing & Packaging</div> <div class="time-estimate"><i class="fas fa-clock"></i> 1.5hrs</div> </div> <div class="step-content"> <div class="description"> Parts undergo Type II anodizing per MIL-A-8625 specification, with color and coating thickness verification. Components are individually wrapped in VCI paper and packed in custom-fit containers with desiccant packs. Each container receives tracking barcode and tamper-evident seal. </div> <div class="safety-warning"> <i class="fas fa-exclamation-triangle"></i> Chemical handling procedures required for anodizing bath. Neutralization station must be operational. </div> </div> </div> <div class="connector"></div> <div class="step distribution" data-step="6"> <div class="step-header"> <div class="step-number">6</div> <div class="step-title">Shipping & Documentation</div> <div class="time-estimate"><i class="fas fa-clock"></i> 55min</div> </div> <div class="step-content"> <div class="description"> Final QA documentation package generation including material certifications, dimensional reports, and traceability records. Shipment preparation includes custom palletization and shock indicators for fragile components. EDI transmission to customer systems for shipment tracking. </div> </div> </div> </div> <div class="legend"> <div class="legend-item"><div class="legend-color color-raw"></div> Raw Materials</div> <div class="legend-item"><div class="legend-color color-prep"></div> Preparation</div> <div class="legend-item"><div class="legend-color color-manuf"></div> Manufacturing</div> <div class="legend-item"><div class="legend-color color-qc"></div> Quality Control</div> <div class="legend-item"><div class="legend-color color-pack"></div> Packaging</div> <div class="legend-item"><div class="legend-color color-dist"></div> Distribution</div> </div> <div class="watermark"> <i class="fas fa-industry"></i> <span>INDUSTRIAL PROCESS SYSTEMS v2.3</span> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Animate steps sequentially const steps = document.querySelectorAll('.step'); steps.forEach((step, index) => { step.style.animationDelay = `${index * 0.15}s`; // Add click event to expand/collapse step.addEventListener('click', function() { toggleStep(this); }); }); // Automatically open the first step setTimeout(() => { toggleStep(steps[0]); }, steps.length * 150 + 200); function toggleStep(step) { const wasActive = step.classList.contains('active'); // Close all steps document.querySelectorAll('.step').forEach(s => { s.classList.remove('active'); }); // If the clicked step wasn't active, open it if (!wasActive) { step.classList.add('active'); // Smooth scroll to the clicked step if it's not visible const flowchart = document.querySelector('.flowchart'); const stepRect = step.getBoundingClientRect(); const containerRect = flowchart.getBoundingClientRect(); if (stepRect.bottom > containerRect.bottom || stepRect.top < containerRect.top) { step.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } } } }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Creative Agency Campaign Flowchart</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Poppins', sans-serif; } body { background-color: #fafafa; width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; overflow: hidden; } .container { width: 700px; height: 700px; position: relative; background: #fff; border-radius: 20px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); overflow: hidden; padding: 20px; } .campaign-header { text-align: center; margin-bottom: 15px; position: relative; } .campaign-header h1 { font-size: 32px; color: #333; margin-bottom: 8px; position: relative; display: inline-block; } .campaign-header h1::after { content: ''; position: absolute; width: 80%; height: 8px; bottom: 0; left: 10%; background: linear-gradient(90deg, #FF6CAB, #7366FF); z-index: -1; opacity: 0.5; border-radius: 10px; } .campaign-header p { font-size: 14px; color: #666; margin-bottom: 10px; max-width: 80%; margin: 0 auto; } .flowchart { position: relative; width: 100%; height: calc(100% - 100px); display: flex; flex-direction: column; justify-content: space-between; align-items: center; padding: 10px 0; } .node { position: relative; padding: 15px 20px; width: 240px; border-radius: 16px; background: #fff; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); cursor: pointer; transition: all 0.3s ease; z-index: 2; text-align: center; opacity: 0; transform: translateY(20px); } .node.animated { opacity: 1; transform: translateY(0); } .node h3 { font-size: 16px; margin-bottom: 8px; color: #333; } .node p { font-size: 12px; color: #666; margin-bottom: 5px; } .icon-container { width: 50px; height: 50px; background: linear-gradient(45deg, var(--start-color), var(--end-color)); border-radius: 50%; position: absolute; top: -20px; left: 50%; transform: translateX(-50%); display: flex; justify-content: center; align-items: center; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); } .icon-container svg { width: 30px; height: 30px; fill: white; } .node:nth-child(1) { --start-color: #FF6CAB; --end-color: #FF9E7D; } .node:nth-child(2) { --start-color: #7366FF; --end-color: #A98EFF; } .node:nth-child(3) { --start-color: #43CBFF; --end-color: #9708CC; } .node:nth-child(4) { --start-color: #FF8135; --end-color: #FF4E50; } .node:nth-child(5) { --start-color: #4FACFE; --end-color: #00F2FE; } .metrics { position: absolute; width: 280px; padding: 20px; background: white; border-radius: 16px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15); top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.9); opacity: 0; pointer-events: none; transition: all 0.3s ease; z-index: 5; } .metrics.active { opacity: 1; transform: translate(-50%, -50%) scale(1); pointer-events: all; } .metrics-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .metrics h3 { font-size: 18px; color: #333; } .close-btn { cursor: pointer; font-size: 24px; color: #666; } .metric-item { margin-bottom: 12px; } .metric-item h4 { font-size: 14px; color: #555; margin-bottom: 5px; display: flex; align-items: center; } .metric-item h4 svg { width: 18px; height: 18px; margin-right: 8px; fill: var(--icon-color); } .metric-item p { font-size: 20px; color: #333; font-weight: bold; } .connections { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; } .connection { position: absolute; top: 0; left: 0; width: 100%; height: 100%; fill: none; stroke-width: 3; stroke-dasharray: 10 5; stroke: #ccc; opacity: 0; transition: opacity 0.5s ease; } .connection.animated { opacity: 1; } .overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 4; opacity: 0; pointer-events: none; transition: opacity 0.3s ease; } .overlay.active { opacity: 1; pointer-events: all; } .hand-drawn { position: absolute; z-index: 0; opacity: 0.1; } .hand-drawn.idea { top: 10%; right: 5%; width: 120px; height: 120px; } .hand-drawn.arrow { bottom: 25%; left: 10%; width: 80px; height: 80px; transform: rotate(45deg); } .hand-drawn.star { top: 30%; left: 7%; width: 60px; height: 60px; animation: float 5s infinite ease-in-out; } @keyframes float { 0%, 100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-20px) rotate(10deg); } } .progress-bar { width: 90%; height: 8px; background: #f0f0f0; border-radius: 4px; margin: 15px auto 5px; position: relative; overflow: hidden; } .progress { height: 100%; border-radius: 4px; background: linear-gradient(45deg, var(--start-color), var(--end-color)); width: 0; transition: width 0.5s ease; } @media (max-width: 700px) { .container { width: 95%; height: 95vh; padding: 15px; } .node { width: 200px; padding: 12px 15px; } .campaign-header h1 { font-size: 24px; } .metrics { width: 240px; } } </style> </head> <body> <div class="container"> <div class="campaign-header"> <h1>Campaign Flow</h1> <p>Navigate our creative campaign journey from concept to results</p> <div class="progress-bar"> <div class="progress"></div> </div> </div> <div class="flowchart"> <!-- Nodes --> <div class="node" data-phase="discovery"> <div class="icon-container"> <svg viewBox="0 0 24 24"> <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/> </svg> </div> <h3>Discovery</h3> <p>Audience insights & market analysis</p> <p>Timeline: 2 weeks</p> </div> <div class="node" data-phase="concept"> <div class="icon-container"> <svg viewBox="0 0 24 24"> <path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/> </svg> </div> <h3>Concept Creation</h3> <p>Brainstorming & creative direction</p> <p>Timeline: 3 weeks</p> </div> <div class="node" data-phase="production"> <div class="icon-container"> <svg viewBox="0 0 24 24"> <path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5.99h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6zm10 14.5V20H8v-3.5l4-4 4 4zm-4-5l-4-4V4h8v3.5l-4 4z"/> </svg> </div> <h3>Production</h3> <p>Asset creation & content development</p> <p>Timeline: 4 weeks</p> </div> <div class="node" data-phase="launch"> <div class="icon-container"> <svg viewBox="0 0 24 24"> <path d="M14 6l-1-2H5v17h2v-7h5l1 2h7V6h-6zm4 8h-4l-1-2H7V6h5l1 2h5v6z"/> </svg> </div> <h3>Launch</h3> <p>Multi-channel activation & deployment</p> <p>Timeline: 1 week</p> </div> <div class="node" data-phase="analysis"> <div class="icon-container"> <svg viewBox="0 0 24 24"> <path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/> </svg> </div> <h3>Analysis</h3> <p>Performance review & optimization</p> <p>Timeline: Ongoing</p> </div> <!-- SVG connection paths --> <svg class="connections"> <path class="connection connection-1" d="M350,140 C390,180 310,220 350,260" /> <path class="connection connection-2" d="M350,280 C390,320 310,360 350,400" /> <path class="connection connection-3" d="M350,420 C390,460 310,500 350,540" /> <path class="connection connection-4" d="M350,560 C390,600 310,640 350,680" /> </svg> <!-- Hand-drawn elements --> <svg class="hand-drawn idea" viewBox="0 0 100 100"> <path d="M50,10 C70,10 85,25 85,45 C85,65 70,75 60,80 C55,82.5 55,85 55,90 L45,90 C45,85 45,82.5 40,80 C30,75 15,65 15,45 C15,25 30,10 50,10 Z" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" /> <line x1="45" y1="95" x2="55" y2="95" stroke="#000" stroke-width="2" stroke-linecap="round" /> <line x1="48" y1="100" x2="52" y2="100" stroke="#000" stroke-width="2" stroke-linecap="round" /> </svg> <svg class="hand-drawn arrow" viewBox="0 0 100 100"> <path d="M10,50 C30,30 70,70 90,50" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" /> <path d="M80,40 L90,50 L80,60" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> <svg class="hand-drawn star" viewBox="0 0 100 100"> <path d="M50,10 L60,40 L90,40 L65,60 L75,90 L50,70 L25,90 L35,60 L10,40 L40,40 Z" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> </div> <!-- Metrics Popup --> <div class="metrics"> <div class="metrics-header"> <h3>Phase Metrics</h3> <div class="close-btn">×</div> </div> <div id="metrics-content"> <!-- Dynamic content will be inserted here --> </div> </div> <!-- Overlay --> <div class="overlay"></div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const nodes = document.querySelectorAll('.node'); const connections = document.querySelectorAll('.connection'); const metrics = document.querySelector('.metrics'); const overlay = document.querySelector('.overlay'); const closeBtn = document.querySelector('.close-btn'); const progressBar = document.querySelector('.progress'); // Animation timeline setTimeout(() => { animateNodes(); animateConnections(); }, 300); function animateNodes() { nodes.forEach((node, index) => { setTimeout(() => { node.classList.add('animated'); updateProgress((index + 1) / nodes.length * 100); }, index * 400); }); } function animateConnections() { connections.forEach((connection, index) => { setTimeout(() => { connection.classList.add('animated'); }, (index + 1) * 400); }); } function updateProgress(percentage) { progressBar.style.width = percentage + '%'; } // Metrics data const metricsData = { discovery: [ { name: 'Audience Segments', value: '5 identified', icon: 'M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z', color: '#FF6CAB' }, { name: 'Market Research', value: '12 competitors analyzed', icon: 'M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-5 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z', color: '#FF6CAB' }, { name: 'Stakeholder Interviews', value: '8 completed', icon: 'M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 12h-2v-2h2v2zm0-4h-2V6h2v4z', color: '#FF6CAB' } ], concept: [ { name: 'Creative Concepts', value: '7 developed', icon: 'M22 11V3h-7v3H9V3H2v8h7V8h2v10h4v3h7v-8h-7v3h-2V8h2v3h7zM7 9H4V5h3v4zm10 6h3v4h-3v-4zm0-10h3v4h-3V5z', color: '#7366FF' }, { name: 'Team Workshops', value: '3 sessions', icon: 'M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z', color: '#7366FF' }, { name: 'Client Approval Time', value: '48 hours', icon: 'M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z', color: '#7366FF' } ], production: [ { name: 'Assets Created', value: '34 deliverables', icon: 'M2 6H0v5h.01L0 20c0 1.1.9 2 2 2h18v-2H2V6zm20-2h-8l-2-2H6c-1.1 0-1.99.9-1.99 2L4 16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM7 15l4.5-6 3.5 4.51 2.5-3.01L21 15H7z', color: '#9708CC' }, { name: 'Content Platforms', value: '6 channels', icon: 'M8 6.82v10.36c0 .79.87 1.27 1.54.84l8.14-5.18c.62-.39.62-1.29 0-1.69L9.54 5.98C8.87 5.55 8 6.03 8 6.82z', color: '#9708CC' }, { name: 'Revision Rounds', value: '2 iterations', icon: 'M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 9.5h7V2.5l-2.35 2.35z', color: '#9708CC' } ], launch: [ { name: 'Launch Date', value: 'May 15, 2023', icon: 'M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z', color: '#FF4E50' }, { name: 'Media Channels', value: '8 platforms', icon: 'M16 6l2.29 2.29-4.88 4.88-4-4L2 16.59 3.41 18l6-6 4 4 6.3-6.29L22 12V6z', color: '#FF4E50' }, { name: 'Initial Reach', value: '2.4M impressions', icon: 'M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z', color: '#FF4E50' } ], analysis: [ { name: 'Engagement Rate', value: '12.8%', icon: 'M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-3.81-3.81-1.33 1.32zm.89-6.52c-.19 0-.37-.03-.52-.08-.16-.06-.29-.13-.4-.24-.11-.1-.2-.22-.26-.37-.06-.14-.09-.3-.09-.47h-1.3c0 .36.07.68.21.95.14.27.33.5.56.69.24.18.51.32.82.41.3.1.62.15.96.15.37 0 .72-.05 1.03-.15.32-.1.6-.25.83-.44s.42-.43.55-.72c.13-.29.2-.61.2-.97 0-.19-.02-.38-.07-.56-.05-.18-.12-.35-.23-.51-.1-.16-.24-.3-.4-.43-.17-.13-.37-.23-.61-.31.2-.09.37-.2.52-.33.15-.13.27-.27.37-.42.1-.15.17-.3.22-.46.05-.16.07-.32.07-.48 0-.36-.06-.68-.18-.96-.12-.28-.29-.51-.51-.69-.2-.19-.47-.33-.77-.43C9.1 8.05 8.76 8 8.39 8c-.36 0-.69.05-1 .16-.3.11-.57.26-.79.45-.21.19-.38.41-.51.67-.12.26-.18.54-.18.85h1.3c0-.17.03-.32.09-.45s.14-.25.25-.34c.11-.09.23-.17.38-.22.15-.05.3-.08.48-.08.4 0 .7.1.89.31.19.2.29.49.29.86 0 .18-.03.34-.08.49-.05.15-.14.27-.25.37-.11.1-.25.18-.41.24-.16.06-.36.09-.58.09H7.5v1.03h.77c.22 0 .42.02.6.07s.33.13.45.23c.12.11.22.24.29.4.07.16.1.35.1.57 0 .41-.12.72-.35.93-.23.23-.55.33-.95.33zm8.55-5.92c-.32-.33-.7-.59-1.14-.77-.43-.18-.92-.27-1.46-.27H12v8h2.3c.55 0 1.06-.09 1.51-.27.45-.18.84-.43 1.16-.76.32-.33.57-.73.74-1.19.17-.47.26-.99.26-1.57v-.4c0-.58-.09-1.1-.26-1.57-.18-.47-.43-.87-.75-1.2zm-.39 3.16c0 .42-.05.79-.14 1.13-.1.33-.24.62-.43.85-.19.23-.43.41-.71.53-.29.12-.62.18-.99.18h-.91V9.12h.97c.72 0 1.27.23 1.64.69.38.46.57 1.12.57 1.99v.4zM12 0l-.66.03 3.81 3.81 1.33-1.33c3.27 1.55 5.61 4.72 5.96 8.48h1.5C23.44 4.84 18.29 0 12 0z', color: '#00F2FE' }, { name: 'Conversion Rate', value: '3.2%', icon: 'M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 2h1.5v3l2-3h1.7l-2 3 2 3h-1.7l-2-3v3H12V5zM7 7.25h2.5V6.5H7V5h4v3.75H8.5v.75H11V11H7V7.25zM19 13l-6 6-4-4-4 4v-2.5l4-4 4 4 6-6V13z', color: '#00F2FE' }, { name: 'ROI', value: '317%', icon: 'M11.8 10.9c-2.27-.59-3-1.2-3-2.15 0-1.09 1.01-1.85 2.7-1.85 1.78 0 2.44.85 2.5 2.1h2.21c-.07-1.72-1.12-3.3-3.21-3.81V3h-3v2.16c-1.94.42-3.5 1.68-3.5 3.61 0 2.31 1.91 3.46 4.7 4.13 2.5.6 3 1.48 3 2.41 0 .69-.49 1.79-2.7 1.79-2.06 0-2.87-.92-2.98-2.1h-2.2c.12 2.19 1.76 3.42 3.68 3.83V21h3v-2.15c1.95-.37 3.5-1.5 3.5-3.55 0-2.84-2.43-3.81-4.7-4.4z', color: '#00F2FE' } ] }; // Show metrics on node click nodes.forEach(node => { node.addEventListener('click', function() { const phase = this.dataset.phase; showMetrics(phase); }); }); // Close metrics and overlay closeBtn.addEventListener('click', hideMetrics); overlay.addEventListener('click', hideMetrics); function showMetrics(phase) { const metricsContent = document.getElementById('metrics-content'); metricsContent.innerHTML = ''; // Generate metrics content based on phase const phaseData = metricsData[phase]; phaseData.forEach(metric => { const metricItem = document.createElement('div'); metricItem.className = 'metric-item'; metricItem.innerHTML = ` <h4 style="--icon-color: ${metric.color}"> <svg viewBox="0 0 24 24"> <path d="${metric.icon}"/> </svg> ${metric.name} </h4> <p>${metric.value}</p> `; metricsContent.appendChild(metricItem); }); // Show metrics and overlay metrics.classList.add('active'); overlay.classList.add('active'); } function hideMetrics() { metrics.classList.remove('active'); overlay.classList.remove('active'); } // Make connections responsive window.addEventListener('resize', updateConnectionPaths); function updateConnectionPaths() { // This would need more complex logic for a fully responsive SVG path // but this is a simplified version const width = document.querySelector('.container').offsetWidth; const centerX = width / 2; connections.forEach((connection, index) => { const y1 = 140 + index * 140; const y2 = y1 + 120; const controlX1 = centerX + 40; const controlX2 = centerX - 40; connection.setAttribute('d', `M${centerX},${y1} C${controlX1},${y1 + 40} ${controlX2},${y2 - 40} ${centerX},${y2}`); }); } // Initial connection path setup setTimeout(updateConnectionPaths, 100); }); </script> </body> </html>