Updated women leading the way section
This commit is contained in:
472
assets/javascript/jquery.cookie.min.js
vendored
472
assets/javascript/jquery.cookie.min.js
vendored
@@ -55,3 +55,475 @@
|
||||
!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 <span class="glowing-rose-text">Intelligence Grid</span> 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 <span class="glowing-rose-text">Neural Backbone</span> 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 = `<span class="time">[${timeStr}]</span> ${isAI ? '<span class="ai">[MileTruth AI]</span> ' : ''}${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);
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user