Mohsin Khan
Initial commit for Hugging Face Docker Spaces
5a58b2b
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Your Health Report | HeartCare</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap"
rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Main Styles -->
<link rel="stylesheet" href="/static/style.css">
<!-- Libraries -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jspdf@2.5.1/dist/jspdf.umd.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<style>
/* Recommendation-specific styles */
.recommendation-page {
padding: 2rem 0;
}
.page-header {
text-align: center;
margin-bottom: 3rem;
animation: fadeInDown 0.8s ease-out;
}
.page-header h1 {
font-size: 2.5rem;
font-weight: 800;
color: var(--text-main);
margin-bottom: 0.5rem;
}
.page-header p {
color: var(--text-muted);
font-size: 1.125rem;
}
.report-grid {
display: grid;
grid-template-columns: 1fr 420px;
gap: 2rem;
margin-bottom: 2rem;
}
@media (max-width: 980px) {
.report-grid {
grid-template-columns: 1fr;
}
.sidebar {
order: -1;
}
}
/* Risk Level Selector */
.risk-selector {
background: white;
padding: 2rem;
border-radius: var(--radius-xl);
box-shadow: var(--shadow-md);
margin-bottom: 2rem;
}
.risk-selector h3 {
font-size: 1.25rem;
font-weight: 700;
margin-bottom: 1rem;
color: var(--text-main);
}
.risk-pills {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 0.75rem;
}
.risk-pill {
padding: 1rem;
border-radius: var(--radius-lg);
color: white;
text-align: center;
cursor: pointer;
font-weight: 600;
transition: all 0.3s ease;
border: 2px solid transparent;
}
.risk-pill:hover {
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
}
.risk-pill.active {
border-color: var(--text-main);
box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.1);
}
.risk-pill.vlow {
background: linear-gradient(135deg, #10B981, #059669);
}
.risk-pill.low {
background: linear-gradient(135deg, #34D399, #10B981);
}
.risk-pill.mod {
background: linear-gradient(135deg, #FBBF24, #F59E0B);
}
.risk-pill.high {
background: linear-gradient(135deg, #FB923C, #F97316);
}
.risk-pill.vh {
background: linear-gradient(135deg, #EF4444, #DC2626);
}
.risk-pill small {
display: block;
font-size: 0.75rem;
opacity: 0.9;
margin-top: 0.25rem;
}
/* Main Report Card */
.report-card {
background: white;
padding: 2.5rem;
border-radius: var(--radius-xl);
box-shadow: var(--shadow-lg);
border-left: 6px solid var(--primary-color);
animation: fadeInUp 0.8s ease-out;
}
.report-card.highlight {
box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.1), var(--shadow-lg);
}
.report-title {
font-size: 1.75rem;
font-weight: 800;
margin-bottom: 0.5rem;
color: var(--text-main);
}
.report-subtitle {
color: var(--text-muted);
margin-bottom: 2rem;
font-size: 1rem;
}
.recommendations-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.5rem;
margin-top: 2rem;
}
.recommendation-card {
background: linear-gradient(135deg, #F8FAFC 0%, #F1F5F9 100%);
padding: 1.5rem;
border-radius: var(--radius-lg);
border: 1px solid var(--border-color);
transition: all 0.3s ease;
}
.recommendation-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-md);
}
.recommendation-card h4 {
font-size: 1.125rem;
font-weight: 700;
margin-bottom: 1rem;
color: var(--primary-color);
display: flex;
align-items: center;
gap: 0.5rem;
}
.recommendation-card ul {
list-style: none;
padding: 0;
margin: 0;
}
.recommendation-card li {
padding: 0.5rem 0;
color: var(--text-main);
display: flex;
align-items: flex-start;
gap: 0.5rem;
}
.recommendation-card li::before {
content: "✓";
color: var(--primary-color);
font-weight: 700;
flex-shrink: 0;
}
/* Sidebar */
.sidebar .card {
background: white;
padding: 1.5rem;
border-radius: var(--radius-xl);
box-shadow: var(--shadow-md);
margin-bottom: 1.5rem;
}
.sidebar h3 {
font-size: 1.125rem;
font-weight: 700;
margin-bottom: 1rem;
color: var(--text-main);
}
/* Severity Meter */
.meter-container {
display: flex;
flex-direction: column;
align-items: center;
padding: 1.5rem 0;
}
.meter {
width: 160px;
height: 160px;
position: relative;
}
.meter svg {
transform: rotate(-90deg);
}
.meter .center {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.meter .percent {
font-size: 2rem;
font-weight: 800;
color: var(--primary-color);
}
.meter .label {
font-size: 0.875rem;
color: var(--text-muted);
margin-top: 0.25rem;
}
/* Chart */
.chart-container {
height: 240px;
margin-top: 1rem;
}
/* Doctor Cards */
.doctor-list {
display: flex;
flex-direction: column;
gap: 1rem;
}
.doctor-card {
padding: 1.25rem;
border-radius: var(--radius-lg);
background: linear-gradient(135deg, #F8FAFC 0%, #F1F5F9 100%);
border: 1px solid var(--border-color);
transition: all 0.3s ease;
}
.doctor-card:hover {
transform: translateX(4px);
box-shadow: var(--shadow-sm);
}
.doctor-name {
font-weight: 700;
color: var(--text-main);
margin-bottom: 0.5rem;
}
.doctor-info {
font-size: 0.875rem;
color: var(--text-muted);
margin-bottom: 0.75rem;
}
.doctor-actions {
display: flex;
gap: 0.5rem;
margin-top: 0.75rem;
}
.btn-small {
padding: 0.5rem 1rem;
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 500;
border: none;
cursor: pointer;
transition: all 0.2s ease;
}
.btn-outline {
background: white;
border: 1px solid var(--border-color);
color: var(--text-main);
}
.btn-outline:hover {
background: var(--bg-body);
}
.btn-primary-small {
background: var(--primary-color);
color: white;
}
.btn-primary-small:hover {
background: var(--primary-hover);
}
/* Map */
#map {
height: 280px;
border-radius: var(--radius-lg);
overflow: hidden;
margin: 1rem 0;
}
/* Action Buttons */
.action-section {
background: white;
padding: 2rem;
border-radius: var(--radius-xl);
box-shadow: var(--shadow-md);
margin-top: 2rem;
}
.action-section h3 {
font-size: 1.25rem;
font-weight: 700;
margin-bottom: 1.5rem;
color: var(--text-main);
}
.action-buttons {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.action-btn {
padding: 0.875rem 1.75rem;
border-radius: 100px;
font-weight: 600;
border: none;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.action-btn-primary {
background: var(--primary-color);
color: white;
box-shadow: 0 4px 6px rgba(79, 70, 229, 0.2);
}
.action-btn-primary:hover {
background: var(--primary-hover);
transform: translateY(-2px);
box-shadow: 0 8px 12px rgba(79, 70, 229, 0.3);
}
/* Priority Factors */
.priority-section {
margin-bottom: 2rem;
animation: fadeInUp 0.9s ease-out;
}
.priority-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1rem;
}
.priority-card {
background: #FEF2F2;
border: 1px solid #FCA5A5;
padding: 1.25rem;
border-radius: var(--radius-lg);
position: relative;
}
.priority-card.warning {
background: #FFFBEB;
border-color: #FCD34D;
}
.priority-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.priority-title {
font-weight: 700;
color: #991B1B;
display: flex;
align-items: center;
gap: 0.5rem;
}
.priority-card.warning .priority-title {
color: #92400E;
}
.priority-value {
font-weight: 800;
font-size: 1.1rem;
}
.priority-desc {
font-size: 0.9rem;
color: var(--text-main);
margin-bottom: 0.5rem;
}
.info-tooltip {
display: inline-block;
cursor: pointer;
color: var(--primary-color);
margin-left: 0.5rem;
}
.explanation-box {
background: white;
padding: 0.75rem;
border-radius: var(--radius-md);
font-size: 0.85rem;
margin-top: 0.5rem;
border-left: 3px solid var(--primary-color);
display: none;
}
.explanation-box.visible {
display: block;
animation: fadeInDown 0.3s ease-out;
}
.action-btn-secondary {
background: white;
color: var(--text-main);
border: 1px solid var(--border-color);
}
.action-btn-secondary:hover {
background: var(--bg-body);
}
/* Animations */
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head>
<body>
<!-- Background Effect -->
<div class="background-glow"></div>
<!-- HEADER -->
<header class="site-header">
<div class="header-container">
<div class="brand">
<span class="heart-icon">❤️</span>
<span class="brand-name">HeartCare</span>
</div>
<nav class="nav-links">
<a href="/">Home</a>
<a href="/#about">About</a>
<a href="/#contact">Contact</a>
<a href="/calculate" class="btn-start">Start Assessment</a>
</nav>
</div>
</header>
<main class="container recommendation-page">
<!-- Page Header -->
<div class="page-header">
<h1>Your Personalized Health Report</h1>
<p>Comprehensive cardiovascular risk assessment with tailored recommendations</p>
</div>
<!-- Risk Level Selector -->
<div class="risk-selector">
<h3>Select Risk Level to View Details</h3>
<p class="small" style="margin-bottom: 1rem;">Click on a risk level below or the system will auto-select based on
your assessment</p>
<div class="risk-pills">
<div class="risk-pill vlow" onclick="show(1)">
Very Low<br><small>0–20%</small>
</div>
<div class="risk-pill low" onclick="show(2)">
Low<br><small>21–40%</small>
</div>
<div class="risk-pill mod" onclick="show(3)">
Moderate<br><small>41–60%</small>
</div>
<div class="risk-pill high" onclick="show(4)">
High<br><small>61–80%</small>
</div>
<div class="risk-pill vh" onclick="show(5)">
Very High<br><small>81–100%</small>
</div>
</div>
</div>
<!-- Main Content Grid -->
<div class="report-grid">
<!-- Left Column: Report Details -->
<div class="main-content">
<div id="detailsArea"></div>
<!-- Action Buttons -->
<div class="action-section">
<h3><i class="fa-solid fa-download"></i> Export & Download</h3>
<div class="action-buttons">
<button class="action-btn action-btn-primary" onclick="downloadDietPDF()">
<i class="fa-solid fa-file-pdf"></i> Download Diet Plan (PDF)
</button>
<button class="action-btn action-btn-secondary" onclick="downloadDietCSV()">
<i class="fa-solid fa-file-csv"></i> Download Diet Plan (CSV)
</button>
<button class="action-btn action-btn-primary" onclick="generatePDF()">
<i class="fa-solid fa-file-medical"></i> Download Full Report (PDF)
</button>
<button class="action-btn action-btn-secondary" onclick="printFriendly()">
<i class="fa-solid fa-print"></i> Print Report
</button>
</div>
</div>
</div>
<!-- Right Column: Sidebar -->
<div class="sidebar">
<!-- Severity Meter -->
<div class="card">
<h3><i class="fa-solid fa-gauge-high"></i> Risk Severity</h3>
<div class="meter-container">
<div class="meter">
<svg width="160" height="160" viewBox="0 0 100 100">
<defs>
<linearGradient id="meterGradient" x1="0" x2="1">
<stop offset="0%" stop-color="#10B981" />
<stop offset="50%" stop-color="#FBBF24" />
<stop offset="100%" stop-color="#EF4444" />
</linearGradient>
</defs>
<circle cx="50" cy="50" r="40" stroke="#E5E7EB" stroke-width="12" fill="none"></circle>
<circle id="meterArc" cx="50" cy="50" r="40" stroke="url(#meterGradient)" stroke-width="12"
stroke-linecap="round" fill="none" stroke-dasharray="0 251.2"></circle>
</svg>
<div class="center">
<div class="percent" id="meterPercent">0%</div>
<div class="label" id="meterLabel">Risk Level</div>
</div>
</div>
</div>
</div>
<!-- Risk Factors Chart -->
<div class="card">
<h3><i class="fa-solid fa-chart-column"></i> Risk Factor Analysis</h3>
<div class="chart-container">
<canvas id="factorChart"></canvas>
</div>
</div>
<!-- Nearby Doctors -->
<div class="card">
<h3><i class="fa-solid fa-user-doctor"></i> Nearby Cardiologists</h3>
<p class="small" style="margin-bottom: 1rem;">Recommended specialists in Nanded, Maharashtra</p>
<div id="map"></div>
<div class="doctor-list" id="doctorList"></div>
</div>
</div>
</div>
</main>
<!-- Footer -->
<footer class="footer">
<div class="footer-container">
<div class="footer-about">
<h3>HeartCare</h3>
<p>HeartCare is a heart disease risk prediction platform created to promote early detection, awareness, and
prevention of cardiovascular diseases.</p>
</div>
<div class="footer-links">
<h4>Quick Links</h4>
<a href="/">Home</a>
<a href="/#about">About</a>
<a href="/#contact">Contact</a>
<a href="/calculate">Start Calculation</a>
</div>
<div class="footer-contact">
<h4>Contact Info</h4>
<p><strong>Email:</strong> support@heartcare.com</p>
<p><strong>Phone:</strong> +91 9876543210</p>
<p><strong>Location:</strong> Nanded, Maharashtra, India</p>
</div>
</div>
<div class="footer-bottom">
<p>&copy; 2025 HeartCare | AI Heart Disease Risk Prediction System | All Rights Reserved</p>
</div>
</footer>
<script>
/* Sample data — Cardiologists in Nanded, MH */
const doctors = [
{ name: "Dr. Shrikant Bhoskar", address: "Sunrise Global Hospital, Nanded", phone: "+91 70454 45363", email: "shrikant@example.com", lat: 19.1683962, lon: 77.3063096 },
{ name: "Dr. Sunil Kamble", address: "Rhythm Heart Care Clinic, Nanded", phone: "+91 92267 30273", email: "sunil@example.com", lat: 19.1574799, lon: 77.3081876 },
{ name: "Dattakrupa Heart Care", address: "Doctor Lane, Khadakpura, Nanded", phone: "+91 93071 27289", email: "dattakrupa@example.com", lat: 19.159009, lon: 77.307444 }
];
const NANDED_LAT = 19.1601;
const NANDED_LON = 77.3040;
/* Recommendation templates */
const PLANS = {
1: {
title: "✅ Very Low Risk (0–20%)",
desc: "Excellent health status! Continue your healthy lifestyle with routine checkups once per year.",
factors: [2, 2, 1, 2, 2],
diet: ["Daily fruits & vegetables", "Whole grains", "Limit processed sugar", "Stay hydrated"],
exercise: ["30 min walk daily", "Yoga/Stretching 3× week", "Light cardio activities"]
},
2: {
title: "🟢 Low Risk (21–40%)",
desc: "Good health with room for improvement. Small lifestyle changes recommended.",
factors: [3, 3, 2, 3, 3],
diet: ["Reduce salt intake", "Increase fiber", "Include omega-3 foods", "Limit saturated fats"],
exercise: ["Brisk walk 30–40 mins daily", "Light resistance training 2× week", "Swimming or cycling"]
},
3: {
title: "🟡 Moderate Risk (41–60%)",
desc: "Preventive action advised. Please consult your doctor for personalized guidance.",
factors: [5, 6, 5, 5, 4],
diet: ["Mediterranean diet", "Avoid fried foods", "Limit red meat", "Increase vegetables"],
exercise: ["Brisk walking 30–45 mins", "Swimming or cycling", "Yoga for stress management"]
},
4: {
title: "🟠 High Risk (61–80%)",
desc: "Cardiologist consultation strongly recommended. Take immediate preventive measures.",
factors: [7, 8, 7, 6, 5],
diet: ["Low sodium & low saturated fat", "Small frequent meals", "Consult dietician", "Avoid processed foods"],
exercise: ["Doctor-approved light exercise only", "Avoid heavy exertion", "Gentle walking"]
},
5: {
title: "🔴 Very High Risk (81–100%)",
desc: "URGENT: Immediate medical attention required. Please visit ER or cardiology specialist now.",
factors: [9, 10, 9, 8, 7],
diet: ["Strict medical diet", "Monitor blood sugar", "Avoid processed foods", "Follow doctor's plan"],
exercise: ["Only doctor-approved minimal activity", "Complete rest if advised"]
}
};
/* Read parameters */
let currentRiskLevel = {{ risk_level }};
const params = new URLSearchParams(location.search);
const riskPercentParam = parseFloat(params.get("risk")) || (currentRiskLevel * 20 - 10);
let factorChartInstance = null;
/* Initialize map */
let map = L.map('map', { scrollWheelZoom: false }).setView([NANDED_LAT, NANDED_LON], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(map);
doctors.forEach((d) => {
const marker = L.marker([d.lat, d.lon]).addTo(map);
marker.bindPopup(`<strong>${d.name}</strong><br>${d.address}<br>Phone: ${d.phone}`);
});
/* Populate doctor list */
function refreshDoctorList() {
const div = document.getElementById('doctorList');
div.innerHTML = '';
doctors.forEach(d => {
const el = document.createElement('div');
el.className = 'doctor-card';
el.innerHTML = `
<div class="doctor-name">${d.name}</div>
<div class="doctor-info">${d.address}</div>
<div class="doctor-info">📞 ${d.phone}</div>
<div class="doctor-actions">
<button class="btn-small btn-outline" onclick="emailDoctor('${d.email}','${d.name}')">
<i class="fa-solid fa-envelope"></i> Email
</button>
<button class="btn-small btn-primary-small" onclick="alertDoctor('${d.email}','${d.name}')">
<i class="fa-solid fa-bell"></i> Send Alert
</button>
</div>
`;
div.appendChild(el);
});
}
refreshDoctorList();
/* Show risk details */
function show(level) {
currentRiskLevel = level;
const data = PLANS[level];
const details = document.getElementById('detailsArea');
// Update active pill
document.querySelectorAll('.risk-pill').forEach(pill => pill.classList.remove('active'));
document.querySelectorAll('.risk-pill')[level - 1].classList.add('active');
const priorityHTML = getPriorityFactorsHTML();
details.innerHTML = `
<div class="report-card highlight" id="detailSection">
<div class="report-title">${data.title}</div>
<div class="report-subtitle">${data.desc}</div>
<div style="background: linear-gradient(135deg, #EEF2FF 0%, #E0E7FF 100%); padding: 1.5rem; border-radius: var(--radius-lg); margin-bottom: 2rem;">
<h4 style="margin: 0 0 0.5rem 0; color: var(--primary-color);"><i class="fa-solid fa-chart-line"></i> Your Risk Score</h4>
<p style="margin: 0; font-size: 2rem; font-weight: 800; color: var(--text-main);" id="predRiskText">--</p>
</div>
${priorityHTML}
<h3 style="margin-bottom: 1.5rem; font-size: 1.5rem;"><i class="fa-solid fa-clipboard-list"></i> Personalized Recommendations</h3>
<div class="recommendations-grid">
<div class="recommendation-card">
<h4><i class="fa-solid fa-utensils"></i> Diet Plan</h4>
<ul>${data.diet.map(i => `<li>${i}</li>`).join('')}</ul>
</div>
<div class="recommendation-card">
<h4><i class="fa-solid fa-dumbbell"></i> Exercise</h4>
<ul>${data.exercise.map(i => `<li>${i}</li>`).join('')}</ul>
</div>
<div class="recommendation-card">
<h4><i class="fa-solid fa-stethoscope"></i> Medical Care</h4>
<ul>
<li>${data.desc}</li>
<li>Recommended tests: BP, Lipid profile, ECG</li>
${level >= 4 ? '<li style="color: #EF4444; font-weight: 600;">Consult cardiologist immediately</li>' : ''}
</ul>
</div>
</div>
</div>
`;
const risk = (typeof riskPercentParam === 'number' && !Number.isNaN(riskPercentParam)) ? riskPercentParam : Math.min(100, Math.max(5, level * 20 - 5));
animateMeter(risk);
document.getElementById('predRiskText').innerText = risk + '%';
renderChart(data.factors);
setTimeout(() => document.getElementById('detailSection').scrollIntoView({ behavior: 'smooth' }), 150);
}
function getPriorityFactorsHTML() {
const factors = [];
// BMI
const bmi = parseFloat(params.get('BMI'));
if (bmi >= 30) {
factors.push({
title: 'High BMI (Obesity)',
value: bmi,
desc: 'A BMI above 30 significantly increases heart disease risk.',
critical: true,
tip: 'Aim for a BMI between 18.5 and 24.9 through calorie deficit and regular exercise.'
});
} else if (bmi >= 25) {
factors.push({
title: 'Overweight',
value: bmi,
desc: 'Being overweight is a modifiable risk factor.',
critical: false,
tip: 'Slight weight loss (5-10%) can produce significant health benefits.'
});
}
// Smoking
if (params.get('Smoking') === '1') {
factors.push({
title: 'Smoking History',
value: 'Yes',
desc: 'Smoking damages blood vessels and reduces oxygen delivery.',
critical: true,
tip: 'Quitting smoking is the most impactful step for heart health. Ask a doctor about cessation aids.'
});
}
// Diabetes
const diabetes = params.get('Diabetes');
if (diabetes === 'Yes' || diabetes === 'During Pregnancy') {
factors.push({
title: 'Diabetes Indicator',
value: diabetes,
desc: 'High blood sugar damages nerves and blood vessels controlling the heart.',
critical: true,
tip: 'Monitor blood sugar daily and adhere to a low-glycemic diet.'
});
}
// Alcohol
const alcohol = parseInt(params.get('Alcohol'));
if (alcohol > 14) {
factors.push({
title: 'High Alcohol Intake',
value: `${alcohol} days/mo`,
desc: 'Excessive alcohol can lead to high blood pressure and heart failure.',
critical: false,
tip: 'Limit alcohol to max 1-2 drinks per occasion or consider abstinence.'
});
}
// Age
const age = parseInt(params.get('Age'));
if (age > 65) {
factors.push({
title: 'Age Factor',
value: `${age} yrs`,
desc: 'Cardiovascular risk naturally increases with age.',
critical: false,
tip: 'More frequent checkups (every 6 months) are recommended for your age group.'
});
}
// Poor Health Perception
const genHealth = params.get('General_Health');
if (genHealth === 'Poor' || genHealth === 'Fair') {
factors.push({
title: 'Self-Reported Health',
value: genHealth,
desc: 'Your self-perception often correlates with underlying issues.',
critical: true,
tip: 'Discuss your specific symptoms (fatigue, pain) with a GP.'
});
}
// Depression
if (params.get('Depression') === '1') {
factors.push({
title: 'Emotional Well-being',
value: 'Depression Indicator',
desc: 'Mental health significantly impacts physical heart health.',
critical: false,
tip: 'Regular exercise and therapy can improve both mood and heart health.'
});
}
// Arthritis
if (params.get('Arthritis') === '1') {
factors.push({
title: 'Chronic Condition',
value: 'Arthritis',
desc: 'Inflammation from arthritis can affect cardiovascular health.',
critical: false,
tip: 'Focus on low-impact activities like swimming to keep the heart healthy without straining joints.'
});
}
// Cancer History
if (params.get('Skin_Cancer') === '1' || params.get('Other_Cancer') === '1') {
factors.push({
title: 'Medical History',
value: 'Cancer Survivor',
desc: 'Prior health challenges require more careful cardiovascular monitoring.',
critical: false,
tip: 'Maintain regular follow-ups with your oncology and cardiology team.'
});
}
if (factors.length === 0) return '';
return `
<div class="priority-section">
<h3 style="color: #991B1B; margin-bottom: 1rem;"><i class="fa-solid fa-triangle-exclamation"></i> Priority Risk Factors</h3>
<div class="priority-grid">
${factors.map((f, i) => `
<div class="priority-card ${f.critical ? '' : 'warning'}">
<div class="priority-header">
<div class="priority-title">
${f.critical ? '<i class="fa-solid fa-circle-exclamation"></i>' : '<i class="fa-solid fa-circle-info"></i>'}
${f.title}
</div>
<div class="priority-value">${f.value}</div>
</div>
<div class="priority-desc">${f.desc}</div>
<div style="font-size: 0.85rem; color: var(--primary-color); font-weight: 600; cursor: pointer;" onclick="toggleExp(${i})">
<i class="fa-regular fa-lightbulb"></i> View Advice
</div>
<div id="exp-${i}" class="explanation-box">
<strong><i class="fa-solid fa-user-doctor"></i> Recommendation:</strong> ${f.tip}
</div>
</div>
`).join('')}
</div>
</div>
`;
}
function toggleExp(i) {
const el = document.getElementById(`exp-${i}`);
el.classList.toggle('visible');
}
/* Animate meter */
function animateMeter(percent) {
const arc = document.getElementById('meterArc');
const meterPercent = document.getElementById('meterPercent');
const circumference = 2 * Math.PI * 40;
const target = Math.max(0, Math.min(100, percent));
const length = (target / 100) * circumference;
let current = 0;
const steps = 50;
const stepVal = length / steps;
if (window.meterAnim) clearInterval(window.meterAnim);
arc.style.strokeDasharray = `0 ${circumference}`;
window.meterAnim = setInterval(() => {
current += stepVal;
const filled = current;
const remain = Math.max(0, circumference - filled);
arc.style.strokeDasharray = `${filled} ${remain}`;
meterPercent.innerText = Math.round((filled / circumference) * 100) + '%';
if (filled >= length - 0.1) {
clearInterval(window.meterAnim);
meterPercent.innerText = Math.round(target) + '%';
}
}, 10);
}
/* Chart.js for factors */
function renderChart(values) {
const ctx = document.getElementById('factorChart').getContext('2d');
if (factorChartInstance) factorChartInstance.destroy();
factorChartInstance = new Chart(ctx, {
type: 'bar',
data: {
labels: ['BMI', 'BP', 'Cholesterol', 'Lifestyle', 'Diet'],
datasets: [{
label: 'Factor Level',
data: values,
backgroundColor: ['#10B981', '#34D399', '#FBBF24', '#FB923C', '#EF4444']
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: { y: { beginAtZero: true, max: 10 } }
}
});
}
/* Download functions */
function downloadDietCSV() {
const lev = currentRiskLevel;
const plan = PLANS[lev];
const rows = [['Type', 'Item'], ...plan.diet.map(i => ['Diet', i]), ...plan.exercise.map(i => ['Exercise', i])];
const csv = rows.map(r => r.map(c => `"${String(c).replace(/"/g, '""')}"`).join(',')).join('\n');
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `heartcare_diet_plan_level_${lev}.csv`;
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
}
async function downloadDietPDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const lev = currentRiskLevel;
const plan = PLANS[lev];
doc.setFontSize(16);
doc.text(`HeartCare - Diet & Exercise Plan`, 14, 20);
doc.setFontSize(14);
doc.text(`${plan.title}`, 14, 30);
doc.setFontSize(12);
let y = 44;
doc.text('Diet Recommendations:', 14, y);
y += 6;
plan.diet.forEach(i => { doc.text(`• ${i}`, 18, y); y += 6; });
y += 4;
doc.text('Exercise Recommendations:', 14, y);
y += 6;
plan.exercise.forEach(i => { doc.text(`• ${i}`, 18, y); y += 6; });
doc.save(`heartcare_diet_plan_level_${lev}.pdf`);
}
function printFriendly() {
window.print();
}
async function generatePDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF({ unit: 'px', format: 'a4' });
const lev = currentRiskLevel;
const plan = PLANS[lev];
const risk = riskPercentParam || (lev * 20 - 10);
doc.setFontSize(20);
doc.text('HeartCare — Health Report', 20, 30);
doc.setFontSize(12);
doc.text(`${plan.title} — Risk: ${risk}%`, 20, 52);
doc.text(`Generated: ${new Date().toLocaleString()}`, 20, 68);
const chartCanvas = document.getElementById('factorChart');
const chartDataUrl = chartCanvas.toDataURL('image/png', 1.0);
doc.addImage(chartDataUrl, 'PNG', 20, 90, 320, 160);
let y = 260;
doc.setFontSize(13);
doc.text('Diet Recommendations:', 20, y);
y += 16;
plan.diet.forEach(i => { doc.setFontSize(11); doc.text('• ' + i, 24, y); y += 12; });
y += 8;
doc.setFontSize(13);
doc.text('Exercise Recommendations:', 20, y);
y += 16;
plan.exercise.forEach(i => { doc.setFontSize(11); doc.text('• ' + i, 24, y); y += 12; });
y += 14;
doc.setFontSize(13);
doc.text('Nearby Doctors:', 20, y);
y += 16;
doctors.forEach(d => {
doc.setFontSize(11);
doc.text(`${d.name} — ${d.address} — ${d.phone}`, 24, y);
y += 12;
});
doc.save(`heartcare_report_level_${lev}.pdf`);
}
function emailDoctor(email, name) {
const lev = currentRiskLevel;
const risk = riskPercentParam || (lev * 20 - 10);
const subject = encodeURIComponent(`HeartCare: Consultation Request — Risk ${risk}%`);
const body = encodeURIComponent(`Dear ${name},\n\nI am contacting you regarding a cardiovascular risk assessment showing ${risk}% risk. Please let me know your available consultation slots.\n\nRegards,\nHeartCare User`);
window.location.href = `mailto:${email}?subject=${subject}&body=${body}`;
}
function alertDoctor(email, name) {
emailDoctor(email, name);
}
/* Initialize */
window.addEventListener('load', () => {
show(currentRiskLevel);
});
</script>
</body>
</html>