/*! * jQuery Cookie Plugin v1.4.1 * https://github.com/carhartl/jquery-cookie * * Copyright 2013 Klaus Hartl * Released under the MIT license */ !function(e) { "function" == typeof define && define.amd ? define(["jquery"], e) : "object" == typeof exports ? e(require("jquery")) : e(jQuery) }(function(e) { var n = /\+/g; function o(e) { return r.raw ? e : encodeURIComponent(e) } function i(e, o) { var i = r.raw ? e : function(e) { 0 === e.indexOf('"') && (e = e.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\")); try { return e = decodeURIComponent(e.replace(n, " ")), r.json ? JSON.parse(e) : e } catch (o) {} }(e); return "function" == typeof o ? o(i) : i } var r = e.cookie = function(n, t, u) { if (t !== undefined && "function" != typeof t) { if ("number" == typeof (u = e.extend({}, r.defaults, u)).expires) { var c = u.expires , f = u.expires = new Date; f.setTime(+f + 864e5 * c) } return document.cookie = [o(n), "=", function(e) { return o(r.json ? JSON.stringify(e) : String(e)) }(t), u.expires ? "; expires=" + u.expires.toUTCString() : "", u.path ? "; path=" + u.path : "", u.domain ? "; domain=" + u.domain : "", u.secure ? "; secure" : ""].join("") } for (var d, a = n ? undefined : {}, p = document.cookie ? document.cookie.split("; ") : [], s = 0, m = p.length; s < m; s++) { var x = p[s].split("=") , y = (d = x.shift(), r.raw ? d : decodeURIComponent(d)) , k = x.join("="); if (n && n === y) { a = i(k, t); break } n || (k = i(k)) === undefined || (a[y] = k) } return a } ; r.defaults = {}, e.removeCookie = function(n, o) { return e.cookie(n) !== undefined && (e.cookie(n, "", e.extend({}, o, { expires: -1 })), !e.cookie(n)) } }); /** * Doormile — Premium Interactive Dashboard Logic * Core Interactions: ALT Vision Toggles, Timeline Hover Highlights, Live AI Routing Simulator */ document.addEventListener('DOMContentLoaded', () => { /* ========================================================================== 1. HEADER NAV SCROLL EFFECTS (For smooth page scrolling) ========================================================================== */ const sections = document.querySelectorAll('section'); // Smooth navigation anchor links document.querySelectorAll('.scroll-arrow-link').forEach(link => { link.addEventListener('click', function(e) { e.preventDefault(); const targetId = this.getAttribute('href'); document.querySelector(targetId).scrollIntoView({ behavior: 'smooth' }); }); }); /* ========================================================================== 2. INTERACTIVE STRATEGIC MOAT ACCORDION ========================================================================== */ const moatCards = document.querySelectorAll('.moat-card'); moatCards.forEach(card => { card.addEventListener('click', () => { // Remove active status from all cards moatCards.forEach(c => c.classList.remove('active')); // Activate current card card.classList.add('active'); }); }); /* ========================================================================== 3. INTERACTIVE ALT VISION TOGGLES (Image 2 exact match) ========================================================================== */ const altPill1 = document.getElementById('alt-pill-1'); const altPill2 = document.getElementById('alt-pill-2'); const visionTitle = document.querySelector('.vision-main-title'); const visionSubtitle = document.querySelector('.vision-main-subtitle'); const vision2030CardHeading = document.querySelector('.glowing-vision-card .card-heading'); const vision2030CardText = document.querySelector('.glowing-vision-card .card-text'); // Alt 1 Copy Data const alt1Data = { title: 'The Intelligence Grid Behind Every Urban Mile', subtitle: 'From Hyderabad EV pilot to nationwide AI logistics intelligence by 2030', cardHeading: 'AI Pulse Layer', cardText: 'Nationwide AI logistics grid reaching 15+ cities, empowering female micro-entrepreneurs.' }; // Alt 2 Copy Data const alt2Data = { title: 'The Neural Backbone Behind Every Urban Mile', subtitle: 'From Hyderabad EV pilot to a full algorithmic urban grid routing infrastructure by 2030', cardHeading: 'Neural Backbone', cardText: 'Resilient node logistics framework connecting metropolitan hubs through dynamic autonomous routing.' }; function applyAltTransition(data, activePill, inactivePill) { activePill.classList.add('active'); inactivePill.classList.remove('active'); // Smooth text transition visionTitle.style.opacity = 0; visionSubtitle.style.opacity = 0; vision2030CardHeading.style.opacity = 0; vision2030CardText.style.opacity = 0; setTimeout(() => { visionTitle.innerHTML = data.title; visionSubtitle.textContent = data.subtitle; vision2030CardHeading.textContent = data.cardHeading; vision2030CardText.textContent = data.cardText; visionTitle.style.opacity = 1; visionSubtitle.style.opacity = 1; vision2030CardHeading.style.opacity = 1; vision2030CardText.style.opacity = 1; }, 200); } // Set transition styles for quick animations [visionTitle, visionSubtitle, vision2030CardHeading, vision2030CardText].forEach(el => { el.style.transition = 'opacity 0.25s ease'; }); altPill1.addEventListener('click', () => { if (!altPill1.classList.contains('active')) { applyAltTransition(alt1Data, altPill1, altPill2); addSimLog('Toggled view to ALT 1: AI Pulse Layer model.', true); } }); altPill2.addEventListener('click', () => { if (!altPill2.classList.contains('active')) { applyAltTransition(alt2Data, altPill2, altPill1); addSimLog('Toggled view to ALT 2: Neural Backbone architecture.', true); } }); /* ========================================================================== 4. TIMELINE HOVER SYNCRONIZATION ========================================================================== */ const roadmapCardsList = document.querySelectorAll('.roadmap-col-card'); const timelineDots = document.querySelectorAll('.node-dot-item'); roadmapCardsList.forEach((card, idx) => { card.addEventListener('mouseenter', () => { // Highlight the corresponding dot on timeline line timelineDots.forEach(d => d.classList.remove('dot-hover')); if (timelineDots[idx]) { timelineDots[idx].classList.add('dot-hover'); // Temporarily expand scale in styling timelineDots[idx].style.transform = 'translate(-50%, -50%) scale(1.5)'; timelineDots[idx].style.transition = 'transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)'; } }); card.addEventListener('mouseleave', () => { if (timelineDots[idx]) { timelineDots[idx].classList.remove('dot-hover'); timelineDots[idx].style.transform = 'translate(-50%, -50%) scale(1)'; } }); }); /* ========================================================================== 5. HTML5 CANVAS: LIVE AI ROUTING SIMULATOR ========================================================================== */ const canvas = document.getElementById('simCanvas'); const ctx = canvas.getContext('2d'); // Controls const toggleManualBtn = document.getElementById('toggle-manual'); const toggleAiBtn = document.getElementById('toggle-ai'); const speedBtn = document.getElementById('sim-speed-btn'); const refreshBtn = document.getElementById('sim-refresh-btn'); const riderCountSpan = document.getElementById('rider-count'); const consoleLogs = document.getElementById('sim-console'); // Metric DOM Handles const simSlaVal = document.getElementById('sim-sla-val'); const simSlaDelta = document.getElementById('sim-sla-delta'); const simSlaProgress = document.getElementById('sim-sla-progress'); const simTimeVal = document.getElementById('sim-time-val'); const simTimeDelta = document.getElementById('sim-time-delta'); const simTimeProgress = document.getElementById('sim-time-progress'); const simCo2Val = document.getElementById('sim-co2-val'); const simCo2Delta = document.getElementById('sim-co2-delta'); const simCo2Progress = document.getElementById('sim-co2-progress'); // Simulation States let isAiMode = false; let animSpeed = 1; // Speed multiplier let networkNodes = []; let riders = []; let lastTime = 0; // Grid System Dimensions function resizeCanvas() { const dpr = window.devicePixelRatio || 1; const rect = canvas.getBoundingClientRect(); canvas.width = rect.width * dpr; canvas.height = rect.height * dpr; ctx.scale(dpr, dpr); } resizeCanvas(); window.addEventListener('resize', resizeCanvas); // Dynamic Log Handler function addSimLog(message, isAI = false) { const timeStr = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }); const logEntry = document.createElement('div'); logEntry.className = 'log-entry'; logEntry.innerHTML = `[${timeStr}] ${isAI ? '[MileTruth AI] ' : ''}${message}`; consoleLogs.appendChild(logEntry); consoleLogs.scrollTop = consoleLogs.scrollHeight; // Keep maximum 8 log entries in terminal if (consoleLogs.childElementCount > 8) { consoleLogs.removeChild(consoleLogs.firstChild); } } // Initialize Network Grid Nodes (Hyderabad Mock Grid) function initNetworkGrid() { networkNodes = []; const width = canvas.width / (window.devicePixelRatio || 1); const height = canvas.height / (window.devicePixelRatio || 1); // Generate central hubs const centralHub = { x: width * 0.5, y: height * 0.5, type: 'central', label: 'Central Hub EV' }; networkNodes.push(centralHub); // Generate suburban delivery clusters const clusterCount = 5; const nodesPerCluster = 5; for (let i = 0; i < clusterCount; i++) { const angle = (i * Math.PI * 2) / clusterCount; const dist = Math.min(width, height) * 0.3; const cx = centralHub.x + Math.cos(angle) * dist; const cy = centralHub.y + Math.sin(angle) * dist; const clusterHub = { x: cx, y: cy, type: 'subhub', label: `Hub Zone ${String.fromCharCode(65 + i)}` }; networkNodes.push(clusterHub); // Inner delivery terminal nodes for (let j = 0; j < nodesPerCluster; j++) { const subAngle = (j * Math.PI * 2) / nodesPerCluster; const subDist = 35 + Math.random() * 25; networkNodes.push({ x: cx + Math.cos(subAngle) * subDist, y: cy + Math.sin(subAngle) * subDist, type: 'delivery', label: `Point ${i}-${j}` }); } } // Spawn EV Rider particles spawnRiders(); } function spawnRiders() { riders = []; const hubNodes = networkNodes.filter(n => n.type === 'central' || n.type === 'subhub'); const deliveryNodes = networkNodes.filter(n => n.type === 'delivery'); const riderCount = 10; riderCountSpan.textContent = `${riderCount} EVs`; for (let i = 0; i < riderCount; i++) { const startHub = hubNodes[Math.floor(Math.random() * hubNodes.length)]; const target = deliveryNodes[Math.floor(Math.random() * deliveryNodes.length)]; riders.push({ x: startHub.x, y: startHub.y, source: startHub, target: target, progress: Math.random(), speed: 0.003 + Math.random() * 0.002, id: `EV-${100 + i}`, color: i % 2 === 0 ? 'rgba(255, 42, 95, 0.95)' : 'rgba(6, 182, 212, 0.95)' }); } } // Grid rendering logic function drawSimulationGrid() { const width = canvas.width / (window.devicePixelRatio || 1); const height = canvas.height / (window.devicePixelRatio || 1); ctx.clearRect(0, 0, width, height); // 1. Draw connecting arterial routes ctx.strokeStyle = 'rgba(255, 255, 255, 0.025)'; ctx.lineWidth = 1; const hubNodes = networkNodes.filter(n => n.type === 'central' || n.type === 'subhub'); ctx.beginPath(); for (let i = 0; i < hubNodes.length; i++) { for (let j = i + 1; j < hubNodes.length; j++) { ctx.moveTo(hubNodes[i].x, hubNodes[i].y); ctx.lineTo(hubNodes[j].x, hubNodes[j].y); } } ctx.stroke(); // 2. Draw active delivery paths ctx.beginPath(); riders.forEach(rider => { if (isAiMode) { ctx.strokeStyle = 'rgba(255, 42, 95, 0.07)'; ctx.lineWidth = 2.5; ctx.moveTo(rider.source.x, rider.source.y); ctx.lineTo(rider.target.x, rider.target.y); } else { ctx.strokeStyle = 'rgba(156, 163, 175, 0.04)'; ctx.lineWidth = 1.5; const midX = (rider.source.x + rider.target.x) / 2 + 50; const midY = (rider.source.y + rider.target.y) / 2 - 50; ctx.moveTo(rider.source.x, rider.source.y); ctx.quadraticCurveTo(midX, midY, rider.target.x, rider.target.y); } }); ctx.stroke(); // 3. Draw grid node points networkNodes.forEach(node => { if (node.type === 'central') { ctx.fillStyle = '#ff2a5f'; ctx.beginPath(); ctx.arc(node.x, node.y, 8, 0, Math.PI * 2); ctx.fill(); ctx.strokeStyle = 'rgba(255, 42, 95, 0.2)'; ctx.lineWidth = 6; ctx.stroke(); } else if (node.type === 'subhub') { ctx.fillStyle = '#06b6d4'; ctx.beginPath(); ctx.arc(node.x, node.y, 5, 0, Math.PI * 2); ctx.fill(); } else { ctx.fillStyle = 'rgba(255, 255, 255, 0.12)'; ctx.beginPath(); ctx.arc(node.x, node.y, 2.5, 0, Math.PI * 2); ctx.fill(); } }); // 4. Animate EV Riders (Moving dots) riders.forEach(rider => { let riderX, riderY; if (isAiMode) { riderX = rider.source.x + (rider.target.x - rider.source.x) * rider.progress; riderY = rider.source.y + (rider.target.y - rider.source.y) * rider.progress; } else { const t = rider.progress; const midX = (rider.source.x + rider.target.x) / 2 + 50; const midY = (rider.source.y + rider.target.y) / 2 - 50; riderX = (1 - t) * (1 - t) * rider.source.x + 2 * (1 - t) * t * midX + t * t * rider.target.x; riderY = (1 - t) * (1 - t) * rider.source.y + 2 * (1 - t) * t * midY + t * t * rider.target.y; } ctx.shadowBlur = 8; ctx.shadowColor = rider.color; ctx.fillStyle = rider.color; ctx.beginPath(); ctx.arc(riderX, riderY, 4.5, 0, Math.PI * 2); ctx.fill(); ctx.shadowBlur = 0; const speedMultiplier = isAiMode ? 1.6 : 1.0; rider.progress += rider.speed * animSpeed * speedMultiplier; if (rider.progress >= 1.0) { const deliveries = networkNodes.filter(n => n.type === 'delivery'); rider.source = rider.target; rider.target = deliveries[Math.floor(Math.random() * deliveries.length)]; rider.progress = 0; rider.speed = 0.003 + Math.random() * 0.002; if (Math.random() > 0.6) { if (isAiMode) { addSimLog(`${rider.id} completed optimized route. SLA Locked.`, true); } else { addSimLog(`${rider.id} delivered package. Latency buffer +3.2s.`, false); } } } }); } // Telemetry dashboard dynamic transitions function updateMetricsDashboard() { if (isAiMode) { simSlaVal.textContent = '98.4%'; simSlaVal.style.color = 'var(--primary-glow)'; simSlaDelta.textContent = '+30.2% vs Manual'; simSlaDelta.className = 'delta'; simSlaProgress.style.width = '98.4%'; simSlaProgress.style.background = 'var(--primary)'; simTimeVal.textContent = '18.2 min'; simTimeVal.style.color = '#fff'; simTimeDelta.textContent = '-24.3 min threshold'; simTimeDelta.className = 'delta'; simTimeProgress.style.width = '24%'; simTimeProgress.style.background = 'var(--primary)'; simCo2Val.textContent = '340 kg'; simCo2Val.style.color = 'var(--accent-glow)'; simCo2Delta.textContent = '+183% baseline'; simCo2Progress.style.width = '92%'; } else { simSlaVal.textContent = '68.2%'; simSlaVal.style.color = 'var(--text-secondary)'; simSlaDelta.textContent = '-30.2% vs AI'; simSlaDelta.className = 'delta negative'; simSlaProgress.style.width = '68.2%'; simSlaProgress.style.background = 'var(--text-muted)'; simTimeVal.textContent = '42.5 min'; simTimeVal.style.color = 'var(--text-secondary)'; simTimeDelta.textContent = '+24.3 min delayed'; simTimeDelta.className = 'delta negative'; simTimeProgress.style.width = '82%'; simTimeProgress.style.background = 'var(--text-muted)'; simCo2Val.textContent = '120 kg'; simCo2Val.style.color = 'var(--text-secondary)'; simCo2Delta.textContent = '+8% baseline'; simCo2Progress.style.width = '35%'; } } // Loop function loop(timestamp) { drawSimulationGrid(); requestAnimationFrame(loop); } // Click triggers toggleManualBtn.addEventListener('click', () => { if (isAiMode) { isAiMode = false; toggleAiBtn.classList.remove('active'); toggleManualBtn.classList.add('active'); addSimLog('Switched to unoptimized Manual Dispatch mode.'); updateMetricsDashboard(); } }); toggleAiBtn.addEventListener('click', () => { if (!isAiMode) { isAiMode = true; toggleManualBtn.classList.remove('active'); toggleAiBtn.classList.add('active'); addSimLog('MileTruth AI optimization activated. Resolving city bottlenecks...', true); updateMetricsDashboard(); } }); speedBtn.addEventListener('click', () => { if (animSpeed === 1) { animSpeed = 2.5; speedBtn.style.color = 'var(--primary-glow)'; addSimLog('Boost mode active. Dispatch rate x2.5.'); } else { animSpeed = 1; speedBtn.style.color = 'var(--text-primary)'; addSimLog('Grid speed returned to normal.'); } }); refreshBtn.addEventListener('click', () => { initNetworkGrid(); addSimLog('Urban network grid re-routed and refreshed.'); }); // Start initNetworkGrid(); requestAnimationFrame(loop); });