<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blood Type Interactive Model By David B</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* Custom styles - kept relatively simple */
.draggable {
touch-action: none;
cursor: grab;
user-select: none; /* Prevent text selection during drag */
}
.dragging {
opacity: 0.5;
cursor: grabbing;
}
.drop-zone {
border: 2px dashed #ccc;
transition: background-color 0.3s ease;
min-height: 50px; /* Ensure drop zones have some height */
}
.drop-zone-hover {
background-color: #e0f2fe;
}
.correct-drop {
background-color: #dcfce7;
border-color: #22c55e;
}
.incorrect-drop {
background-color: #fee2e2;
border-color: #ef4444;
}
.clumped {
background-color: #fecaca;
background-image: radial-gradient(#ef4444 20%, transparent 20%),
radial-gradient(#ef4444 20%, transparent 20%);
background-size: 10px 10px;
background-position: 0 0, 5px 5px;
border: 1px solid #dc2626;
}
.not-clumped {
background-color: #fda4af;
border: 1px solid #f43f5e;
}
/* Styling for Hemostasis steps */
.step-source .step {
background-color: #e0e7ff; /* Light indigo */
border: 1px solid #a5b4fc; /* Indigo */
cursor: grab; /* Ensure steps in source are grabbable */
}
.step-target .step {
background-color: #f3f4f6; /* Light gray */
border: 1px solid #d1d5db; /* Gray */
cursor: default; /* Steps in target are not grabbable */
}
.step-target.correct-sequence .step {
background-color: #dcfce7; /* Light green */
border: 1px solid #86efac; /* Green */
}
</style>
</head>
<body class="font-[Inter,sans-serif] bg-gray-100 text-gray-800">
<div class="container mx-auto p-4 md:p-8">
<header class="bg-red-600 text-white p-6 rounded-lg shadow-md mb-8">
<h1 class="text-3xl md:text-4xl font-bold">Blood Type Interactive Model By David B</h1>
<p class="mt-2 text-lg">Your interactive guide to the world of blood!</p>
</header>
<nav class="mb-8 bg-white p-4 rounded-lg shadow-sm">
<ul class="flex flex-wrap gap-2 justify-center">
<li><button onclick="showPage('home')" class="nav-button bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition duration-300">Home</button></li>
<li><button onclick="showPage('components')" class="nav-button bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition duration-300">Components</button></li>
<li><button onclick="showPage('types')" class="nav-button bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition duration-300">Blood Types</button></li>
<li><button onclick="showPage('inheritance')" class="nav-button bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition duration-300">Inheritance</button></li>
<li><button onclick="showPage('transfusions')" class="nav-button bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition duration-300">Transfusions</button></li>
<li><button onclick="showPage('hemostasis')" class="nav-button bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition duration-300">Hemostasis</button></li>
<li><button onclick="showPage('quiz')" class="nav-button bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition duration-300">Quiz</button></li>
</ul>
</nav>
<main id="page-content" class="bg-white p-6 rounded-lg shadow-md min-h-[400px]">
<div id="home" class="page active-page">
<h2 class="text-2xl font-semibold mb-4 text-red-700">Welcome!</h2>
<p class="mb-4">welcome to this website about blood basics, in witch ill do my best to teach you about soothing I learned about 2 hrs ago! I hope most of this is correct, but at this point im on so much caffeine, and its 3 am, so yea :.3.</p>
<p class="mb-4">There is no prior knowledge needed, everything you should need should be on here(I hope)</p>
<p>Use the buttons above to navigate through the different topics.</p>
<div class="mt-6 text-center">
<svg class="inline-block w-24 h-24 text-red-500" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z" clip-rule="evenodd" />
</svg>
<p class="mt-2 font-semibold">Blood is essential for life!</p>
</div>
</div>
<div id="components" class="page hidden">
<h2 class="text-2xl font-semibold mb-4 text-red-700">What's in Blood? - The Components</h2>
<p class="mb-4">Blood might look like just red liquid, but it's actually a complex mixture.</p>
<p class="mb-2">The liquid part is called <strong>Plasma</strong>. It's mostly water, but carries nutrients, hormones, and proteins.</p>
<p class="mb-4">Floating in the plasma are different types of cells and fragments:</p>
<ul class="list-disc list-inside mb-4 space-y-2">
<li><strong>Red Blood Cells (RBCs):</strong> Carry oxygen. Most numerous.</li>
<li><strong>White Blood Cells (WBCs):</strong> Fight infections. Body's defense force.</li>
<li><strong>Platelets:</strong> Tiny fragments that help blood clot.</li>
</ul>
<h3 class="text-xl font-semibold mb-2">Activity: Build-A-Blood-Drop</h3>
<p class="mb-4 text-sm text-gray-600">Drag components into the Plasma pool below to see what blood contains. You can add multiple copies of each component (like many RBCs!). Click a component in the pool to learn its function.</p>
<div class="flex flex-col md:flex-row gap-4 items-start">
<div class="flex flex-row md:flex-col gap-2 mb-4 md:mb-0 p-4 border border-gray-300 rounded-lg bg-gray-50">
<p class="font-semibold mb-2 text-center md:text-left">Drag These:</p>
<div id="drag-rbc" draggable="true" class="draggable p-2 bg-red-400 text-white rounded shadow cursor-grab text-center" data-info="Red Blood Cell: Carries Oxygen.">RBC</div>
<div id="drag-wbc" draggable="true" class="draggable p-2 bg-blue-400 text-white rounded shadow cursor-grab text-center" data-info="White Blood Cell: Fights infection. Part of the immune system.">WBC</div>
<div id="drag-platelet" draggable="true" class="draggable p-2 bg-yellow-400 text-gray-800 rounded shadow cursor-grab text-center" data-info="Platelet: Small fragment that helps blood clot.">Platelet</div>
</div>
<div id="plasma-pool" class="drop-zone flex-grow min-h-[200px] p-4 bg-yellow-100 rounded-lg border-2 border-dashed border-yellow-400 relative">
<p class="absolute top-2 left-2 text-yellow-700 font-semibold">Plasma Pool</p>
</div>
<div id="component-info" class="w-full md:w-1/3 p-4 border border-gray-300 rounded-lg bg-gray-50 min-h-[100px]">
<p class="font-semibold mb-2">Component Info:</p>
<p id="info-text" class="text-gray-700">Click on a component in the pool to see its info here.</p>
</div>
</div>
</div>
<div id="types" class="page hidden">
<h2 class="text-2xl font-semibold mb-4 text-red-700">Blood Types - ABO & Rh</h2>
<p class="mb-4">Your blood type is like an ID tag for your red blood cells, determined by markers called <strong>Antigens</strong>.</p>
<h3 class="text-xl font-semibold mb-2">ABO System</h3>
<ul class="list-disc list-inside mb-2 space-y-1">
<li>Type A: Has A antigens, Anti-B antibodies.</li>
<li>Type B: Has B antigens, Anti-A antibodies.</li>
<li>Type AB: Has BOTH A and B antigens, NO ABO antibodies.</li>
<li>Type O: Has NEITHER A nor B antigens, BOTH Anti-A and Anti-B antibodies.</li>
</ul>
<h3 class="text-xl font-semibold mb-2">Rh System</h3>
<ul class="list-disc list-inside mb-4 space-y-1">
<li>Rh Positive (+): Has the Rh antigen.</li>
<li>Rh Negative (-): Does NOT have the Rh antigen. Can develop Anti-Rh antibodies if exposed to Rh+ blood.</li>
</ul>
<h3 class="text-xl font-semibold mb-2">What is Agglutination?</h3>
<p class="mb-4 p-4 bg-red-100 border border-red-300 rounded-lg">
<strong>Agglutination</strong> means 'clumping together'. This happens when antibodies in plasma encounter the specific antigens they target on red blood cells (e.g., Anti-A antibodies + Type A RBCs = Clumping). This is dangerous inside the body as it blocks blood flow.
</p>
<h3 class="text-xl font-semibold mb-2">Activity: Virtual Blood Typing Lab</h3>
<p class="mb-4 text-sm text-gray-600">Add virtual 'Anti-A', 'Anti-B', and 'Anti-Rh' serums to each sample. Observe if <strong>agglutination</strong> (clumping) occurs. Determine the blood type using the results and the chart.</p>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
<div class="border p-4 rounded-lg shadow-sm bg-gray-50">
<h4 class="font-semibold mb-3 text-center">Sample 1 (<span class="sample-type" data-type="A+">???</span>)</h4>
<div class="flex justify-around mb-3">
<div class="text-center">
<div id="s1-anti-a" class="w-12 h-12 rounded-full mx-auto mb-1 border border-gray-400 not-clumped"></div>
<button onclick="addSerum('s1', 'anti-a', 'A+')" class="text-xs bg-blue-500 hover:bg-blue-700 text-white px-2 py-1 rounded">Anti-A</button>
</div>
<div class="text-center">
<div id="s1-anti-b" class="w-12 h-12 rounded-full mx-auto mb-1 border border-gray-400 not-clumped"></div>
<button onclick="addSerum('s1', 'anti-b', 'A+')" class="text-xs bg-yellow-500 hover:bg-yellow-700 text-white px-2 py-1 rounded">Anti-B</button>
</div>
<div class="text-center">
<div id="s1-anti-rh" class="w-12 h-12 rounded-full mx-auto mb-1 border border-gray-400 not-clumped"></div>
<button onclick="addSerum('s1', 'anti-rh', 'A+')" class="text-xs bg-green-500 hover:bg-green-700 text-white px-2 py-1 rounded">Anti-Rh</button>
</div>
</div>
<div class="text-center">
<label for="s1-guess" class="mr-2">Guess:</label>
<select id="s1-guess" class="border rounded p-1">
<option value="">Select</option>
<option value="A+">A+</option> <option value="A-">A-</option>
<option value="B+">B+</option> <option value="B-">B-</option>
<option value="AB+">AB+</option> <option value="AB-">AB-</option>
<option value="O+">O+</option> <option value="O-">O-</option>
</select>
<button onclick="checkType('s1', 'A+')" class="bg-gray-500 hover:bg-gray-700 text-white px-2 py-1 rounded ml-2">Check</button>
</div>
<p id="s1-feedback" class="text-center mt-2 text-sm font-semibold"> </p>
</div>
<div class="border p-4 rounded-lg shadow-sm bg-gray-50">
<h4 class="font-semibold mb-3 text-center">Sample 2 (<span class="sample-type" data-type="O-">???</span>)</h4>
<div class="flex justify-around mb-3">
<div class="text-center">
<div id="s2-anti-a" class="w-12 h-12 rounded-full mx-auto mb-1 border border-gray-400 not-clumped"></div>
<button onclick="addSerum('s2', 'anti-a', 'O-')" class="text-xs bg-blue-500 hover:bg-blue-700 text-white px-2 py-1 rounded">Anti-A</button>
</div>
<div class="text-center">
<div id="s2-anti-b" class="w-12 h-12 rounded-full mx-auto mb-1 border border-gray-400 not-clumped"></div>
<button onclick="addSerum('s2', 'anti-b', 'O-')" class="text-xs bg-yellow-500 hover:bg-yellow-700 text-white px-2 py-1 rounded">Anti-B</button>
</div>
<div class="text-center">
<div id="s2-anti-rh" class="w-12 h-12 rounded-full mx-auto mb-1 border border-gray-400 not-clumped"></div>
<button onclick="addSerum('s2', 'anti-rh', 'O-')" class="text-xs bg-green-500 hover:bg-green-700 text-white px-2 py-1 rounded">Anti-Rh</button>
</div>
</div>
<div class="text-center">
<label for="s2-guess" class="mr-2">Guess:</label>
<select id="s2-guess" class="border rounded p-1">
<option value="">Select</option>
<option value="A+">A+</option> <option value="A-">A-</option>
<option value="B+">B+</option> <option value="B-">B-</option>
<option value="AB+">AB+</option> <option value="AB-">AB-</option>
<option value="O+">O+</option> <option value="O-">O-</option>
</select>
<button onclick="checkType('s2', 'O-')" class="bg-gray-500 hover:bg-gray-700 text-white px-2 py-1 rounded ml-2">Check</button>
</div>
<p id="s2-feedback" class="text-center mt-2 text-sm font-semibold"> </p>
</div>
<div class="border p-4 rounded-lg shadow-sm bg-gray-50">
<h4 class="font-semibold mb-3 text-center">Sample 3 (<span class="sample-type" data-type="AB+">???</span>)</h4>
<div class="flex justify-around mb-3">
<div class="text-center">
<div id="s3-anti-a" class="w-12 h-12 rounded-full mx-auto mb-1 border border-gray-400 not-clumped"></div>
<button onclick="addSerum('s3', 'anti-a', 'AB+')" class="text-xs bg-blue-500 hover:bg-blue-700 text-white px-2 py-1 rounded">Anti-A</button>
</div>
<div class="text-center">
<div id="s3-anti-b" class="w-12 h-12 rounded-full mx-auto mb-1 border border-gray-400 not-clumped"></div>
<button onclick="addSerum('s3', 'anti-b', 'AB+')" class="text-xs bg-yellow-500 hover:bg-yellow-700 text-white px-2 py-1 rounded">Anti-B</button>
</div>
<div class="text-center">
<div id="s3-anti-rh" class="w-12 h-12 rounded-full mx-auto mb-1 border border-gray-400 not-clumped"></div>
<button onclick="addSerum('s3', 'anti-rh', 'AB+')" class="text-xs bg-green-500 hover:bg-green-700 text-white px-2 py-1 rounded">Anti-Rh</button>
</div>
</div>
<div class="text-center">
<label for="s3-guess" class="mr-2">Guess:</label>
<select id="s3-guess" class="border rounded p-1">
<option value="">Select</option>
<option value="A+">A+</option> <option value="A-">A-</option>
<option value="B+">B+</option> <option value="B-">B-</option>
<option value="AB+">AB+</option> <option value="AB-">AB-</option>
<option value="O+">O+</option> <option value="O-">O-</option>
</select>
<button onclick="checkType('s3', 'AB+')" class="bg-gray-500 hover:bg-gray-700 text-white px-2 py-1 rounded ml-2">Check</button>
</div>
<p id="s3-feedback" class="text-center mt-2 text-sm font-semibold"> </p>
</div>
</div>
<h4 class="text-lg font-semibold mb-2">Reference Chart:</h4>
<div class="overflow-x-auto">
<table class="w-full border-collapse border border-gray-300 text-left text-sm">
<thead>
<tr class="bg-red-200">
<th class="border border-gray-300 p-2">Clumps w/ Anti-A?</th>
<th class="border border-gray-300 p-2">Clumps w/ Anti-B?</th>
<th class="border border-gray-300 p-2">Clumps w/ Anti-Rh?</th>
<th class="border border-gray-300 p-2">Blood Type</th>
</tr>
</thead>
<tbody>
<tr class="bg-white"><td>Yes</td><td>No</td><td>Yes</td><td>A+</td></tr>
<tr class="bg-gray-50"><td>Yes</td><td>No</td><td>No</td><td>A-</td></tr>
<tr class="bg-white"><td>No</td><td>Yes</td><td>Yes</td><td>B+</td></tr>
<tr class="bg-gray-50"><td>No</td><td>Yes</td><td>No</td><td>B-</td></tr>
<tr class="bg-white"><td>Yes</td><td>Yes</td><td>Yes</td><td>AB+</td></tr>
<tr class="bg-gray-50"><td>Yes</td><td>Yes</td><td>No</td><td>AB-</td></tr>
<tr class="bg-white"><td>No</td><td>No</td><td>Yes</td><td>O+</td></tr>
<tr class="bg-gray-50"><td>No</td><td>No</td><td>No</td><td>O-</td></tr>
</tbody>
</table>
</div>
</div>
<div id="inheritance" class="page hidden">
<h2 class="text-2xl font-semibold mb-4 text-red-700">Blood Type Inheritance</h2>
<p class="mb-4">Your blood type is inherited via genes from your parents. You get one ABO gene (A, B, or O) and one Rh gene (+ or -) from each parent.</p>
<ul class="list-disc list-inside mb-4 space-y-1 bg-blue-50 p-4 rounded border border-blue-200">
<li><strong>ABO Dominance:</strong> A and B are dominant over O. A and B are co-dominant (both show). O is recessive (need two O genes for Type O).</li>
<li><strong>Rh Dominance:</strong> Rh+ is dominant over Rh-. Need two Rh- genes for Rh Negative.</li>
<li>This means children can have different blood types than their parents! (e.g., A parent (with AO genes) + B parent (with BO genes) can have an O child (OO)).</li>
</ul>
<h3 class="text-xl font-semibold mb-2">Activity: Blood Type Inheritance Predictor</h3>
<p class="mb-4 text-sm text-gray-600">Select the blood types for two parents to see the possible blood types their children could have (based on common gene combinations).</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-4 p-4 border rounded-lg bg-gray-50">
<div>
<h4 class="font-semibold mb-2">Parent 1</h4>
<label for="p1-abo" class="mr-2">ABO:</label>
<select id="p1-abo" class="border rounded p-1 mb-2">
<option value="A">A</option> <option value="B">B</option> <option value="AB">AB</option> <option value="O">O</option>
</select>
<label for="p1-rh" class="ml-4 mr-2">Rh:</label>
<select id="p1-rh" class="border rounded p-1 mb-2">
<option value="+">+</option> <option value="-">-</option>
</select>
</div>
<div>
<h4 class="font-semibold mb-2">Parent 2</h4>
<label for="p2-abo" class="mr-2">ABO:</label>
<select id="p2-abo" class="border rounded p-1 mb-2">
<option value="A">A</option> <option value="B">B</option> <option value="AB">AB</option> <option value="O">O</option>
</select>
<label for="p2-rh" class="ml-4 mr-2">Rh:</label>
<select id="p2-rh" class="border rounded p-1 mb-2">
<option value="+">+</option> <option value="-">-</option>
</select>
</div>
</div>
<div class="text-center mb-4">
<button onclick="calculateInheritance()" class="bg-green-600 hover:bg-green-800 text-white font-bold py-2 px-6 rounded transition duration-300">Calculate Possibilities</button>
</div>
<div id="inheritance-results" class="p-4 border rounded-lg bg-green-50 border-green-200 min-h-[100px]">
<h4 class="font-semibold mb-2 text-green-800">Possible Child Blood Types:</h4>
<p id="possible-types-text">Select parent types and click calculate.</p>
</div>
</div>
<div id="transfusions" class="page hidden">
<h2 class="text-2xl font-semibold mb-4 text-red-700">Why Transfusions Matter</h2>
<p class="mb-4">A blood transfusion is giving donor blood to a recipient. Correct matching is VITAL.</p>
<p class="mb-4 p-4 bg-red-100 border border-red-300 rounded-lg">
<strong>Why? Agglutination!</strong> If a recipient gets incompatible blood, their antibodies attack the donor's antigens, causing dangerous clumping (agglutination) that blocks blood vessels. This can be fatal.
</p>
<h3 class="text-lg font-semibold mb-2">General Compatibility Rules:</h3>
<ul class="list-disc list-inside mb-4 space-y-1">
<li><strong>Type O-</strong> is often called the Universal Donor (no A, B, or Rh antigens to attack).</li>
<li><strong>Type AB+</strong> is often called the Universal Recipient (no Anti-A, Anti-B, or Anti-Rh antibodies to attack donated cells).</li>
<li>Rh- people should ideally get Rh- blood. Rh+ people can get Rh+ or Rh-.</li>
<li>The recipient's antibodies must not attack the donor's antigens.</li>
</ul>
<h3 class="text-xl font-semibold mb-2">Activity: Safe Transfusion Simulation</h3>
<p class="mb-4 text-sm text-gray-600">Your patient needs blood! Their type is shown. Drag compatible blood bag(s) from the 'Blood Bank' to the patient. Avoid dangerous mismatches!</p>
<div class="flex flex-col md:flex-row gap-6 items-start">
<div class="w-full md:w-1/3 p-4 border rounded-lg bg-blue-100 text-center">
<h4 class="font-semibold mb-2">Patient</h4>
<div class="text-4xl font-bold text-blue-700 mb-2" id="patient-blood-type">B+</div>
<svg class="inline-block w-16 h-16 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path></svg>
<div id="transfusion-drop-zone" class="drop-zone mt-4 p-4 min-h-[80px] bg-blue-50 border-blue-300">Drop Bag Here</div>
<p id="transfusion-feedback" class="mt-2 font-semibold h-8"> </p>
<button onclick="changePatientType()" class="mt-2 text-sm bg-gray-400 hover:bg-gray-600 text-white px-3 py-1 rounded">New Patient</button>
</div>
<div class="w-full md:w-2/3 p-4 border rounded-lg bg-gray-50">
<h4 class="font-semibold mb-3 text-center">Blood Bank (Drag a bag to the patient)</h4>
<div id="blood-bank" class="grid grid-cols-2 sm:grid-cols-4 gap-4">
</div>
</div>
</div>
</div>
<div id="hemostasis" class="page hidden">
<h2 class="text-2xl font-semibold mb-4 text-red-700">Hemostasis - Stopping the Bleeding</h2>
<p class="mb-4">When you get a cut, your body acts fast to stop the bleeding. This process is called <strong>Hemostasis</strong>. It involves several steps:</p>
<ol class="list-decimal list-inside mb-4 space-y-2">
<li><strong>Vascular Spasm:</strong> The damaged blood vessel constricts (squeezes) immediately to reduce blood flow.</li>
<li><strong>Platelet Plug Formation:</strong> Tiny cell fragments called platelets stick to the damaged site and to each other, forming a temporary plug.</li>
<li><strong>Coagulation (Blood Clotting):</strong> This is a complex process involving clotting factors in the plasma. The end result is the formation of **fibrin**, a protein that forms a mesh over the platelet plug, trapping blood cells and making the clot stronger.</li>
<li><strong>Clot Retraction and Repair:</strong> The clot gradually shrinks, pulling the edges of the damaged vessel closer together. Eventually, the vessel wall repairs itself, and the clot dissolves.</li>
</ol>
<h3 class="text-xl font-semibold mb-2">Activity: Sequence the Hemostasis Steps</h3>
<p class="mb-4 text-sm text-gray-600">Drag the steps from the 'Steps Pool' into the correct order in the 'Sequence Area' below.</p>
<div class="flex flex-col md:flex-row gap-6 items-start">
<div id="hemostasis-steps-source" class="w-full md:w-1/3 p-4 border rounded-lg bg-gray-50 space-y-2 step-source">
<p class="font-semibold mb-2">Steps Pool (Drag these):</p>
</div>
<div class="w-full md:w-2/3 p-4 border rounded-lg bg-blue-50 space-y-2 step-target">
<p class="font-semibold mb-2 text-blue-800">Sequence Area (Drop in order):</p>
<div id="step-target-1" class="drop-zone p-2 border-blue-300 rounded" data-order="1">1. </div>
<div id="step-target-2" class="drop-zone p-2 border-blue-300 rounded" data-order="2">2. </div>
<div id="step-target-3" class="drop-zone p-2 border-blue-300 rounded" data-order="3">3. </div>
<div id="step-target-4" class="drop-zone p-2 border-blue-300 rounded" data-order="4">4. </div>
<p id="hemostasis-feedback" class="mt-2 font-semibold text-center"> </p>
<button onclick="checkHemostasisSequence()" class="mt-2 bg-blue-500 hover:bg-blue-700 text-white px-3 py-1 rounded block mx-auto">Check Sequence</button>
<button onclick="resetHemostasis()" class="mt-2 text-sm bg-gray-400 hover:bg-gray-600 text-white px-3 py-1 rounded block mx-auto">Reset</button>
</div>
</div>
</div>
<div id="quiz" class="page hidden">
<h2 class="text-2xl font-semibold mb-4 text-red-700">Quiz Yourself!</h2>
<p class="mb-6">Test your knowledge! Choose the best answer for each question.</p>
<div id="quiz-questions" class="space-y-6">
<div class="quiz-question border p-4 rounded-lg bg-gray-50">
<p class="font-semibold mb-2">1. What is the main job of Red Blood Cells?</p>
<div class="space-y-1">
<label class="block"><input type="radio" name="q1" value="a"> a) Fight Infection</label>
<label class="block"><input type="radio" name="q1" value="b" data-correct="true"> b) Carry Oxygen</label>
<label class="block"><input type="radio" name="q1" value="c"> c) Clot Blood</label>
</div>
<p class="quiz-feedback mt-2 text-sm font-semibold"> </p>
</div>
<div class="quiz-question border p-4 rounded-lg bg-gray-50">
<p class="font-semibold mb-2">2. Which part of blood contains antibodies?</p>
<div class="space-y-1">
<label class="block"><input type="radio" name="q2" value="a"> a) Red Blood Cells</label>
<label class="block"><input type="radio" name="q2" value="b"> b) White Blood Cells</label>
<label class="block"><input type="radio" name="q2" value="c" data-correct="true"> c) Plasma</label>
<label class="block"><input type="radio" name="q2" value="d"> d) Platelets</label>
</div>
<p class="quiz-feedback mt-2 text-sm font-semibold"> </p>
</div>
<div class="quiz-question border p-4 rounded-lg bg-gray-50">
<p class="font-semibold mb-2">3. What happens when Anti-B antibodies mix with B antigens?</p>
<div class="space-y-1">
<label class="block"><input type="radio" name="q3" value="a"> a) Nothing</label>
<label class="block"><input type="radio" name="q3" value="b" data-correct="true"> b) Agglutination (Clumping)</label>
<label class="block"><input type="radio" name="q3" value="c"> c) Oxygen Release</label>
</div>
<p class="quiz-feedback mt-2 text-sm font-semibold"> </p>
</div>
<div class="quiz-question border p-4 rounded-lg bg-gray-50">
<p class="font-semibold mb-2">4. A person with Type O- blood is often called a...?</p>
<div class="space-y-1">
<label class="block"><input type="radio" name="q4" value="a" data-correct="true"> a) Universal Donor</label>
<label class="block"><input type="radio" name="q4" value="b"> b) Universal Recipient</label>
<label class="block"><input type="radio" name="q4" value="c"> c) Common Ancestor</label>
</div>
<p class="quiz-feedback mt-2 text-sm font-semibold"> </p>
</div>
<div class="quiz-question border p-4 rounded-lg bg-gray-50">
<p class="font-semibold mb-2">5. What is the main goal of Hemostasis?</p>
<div class="space-y-1">
<label class="block"><input type="radio" name="q5" value="a"> a) Carry Oxygen</label>
<label class="block"><input type="radio" name="q5" value="b" data-correct="true"> b) Stop Bleeding</label>
<label class="block"><input type="radio" name="q5" value="c"> c) Fight Infection</label>
</div>
<p class="quiz-feedback mt-2 text-sm font-semibold"> </p>
</div>
<div class="quiz-question border p-4 rounded-lg bg-gray-50">
<p class="font-semibold mb-2">6. Which component forms the initial temporary blockage in Hemostasis?</p>
<div class="space-y-1">
<label class="block"><input type="radio" name="q6" value="a"> a) Red Blood Cells</label>
<label class="block"><input type="radio" name="q6" value="b"> b) Fibrin</label>
<label class="block"><input type="radio" name="q6" value="c" data-correct="true"> c) Platelet Plug</label>
</div>
<p class="quiz-feedback mt-2 text-sm font-semibold"> </p>
</div>
</div>
<div class="mt-8 text-center">
<button onclick="submitQuiz()" class="bg-blue-600 hover:bg-blue-800 text-white font-bold py-2 px-6 rounded transition duration-300">Submit Answers</button>
<p id="quiz-results" class="mt-4 text-xl font-semibold"> </p>
</div>
</div>
</main>
<footer class="mt-8 text-center text-sm text-gray-500">
<p>This is a interactive website for anatomy, by David B, coded mostly by me, with some help from chat gtp</p>
</footer>
</div>
<script>
// --- Page Navigation ---
function showPage(pageId) {
document.querySelectorAll('.page').forEach(page => {
page.classList.add('hidden');
page.classList.remove('active-page');
});
const activePage = document.getElementById(pageId);
if (activePage) {
activePage.classList.remove('hidden');
activePage.classList.add('active-page');
}
document.querySelectorAll('.nav-button').forEach(button => {
button.classList.remove('bg-red-700');
button.classList.add('bg-red-500');
});
const activeButton = document.querySelector(`button[onclick="showPage('${pageId}')"]`);
if(activeButton) {
activeButton.classList.remove('bg-red-500');
activeButton.classList.add('bg-red-700');
}
}
// --- Drag and Drop Logic ---
let draggedItem = null;
function setupDragAndDrop() {
const draggables = document.querySelectorAll('.draggable');
const dropZones = document.querySelectorAll('.drop-zone');
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', (e) => {
// Don't allow dragging from target zones in Hemostasis
if (draggable.closest('.step-target')) {
e.preventDefault();
return;
}
draggedItem = e.target;
// Apply dragging style slightly later to avoid flicker
setTimeout(() => {
if (draggedItem) draggedItem.classList.add('dragging');
} , 0);
// Set data based on context
if (e.target.hasAttribute('data-info')) { // Component Builder
e.dataTransfer.setData('text/plain', e.target.id);
e.dataTransfer.setData('info', e.target.getAttribute('data-info'));
} else if (e.target.hasAttribute('data-blood-type')) { // Transfusion
e.dataTransfer.setData('text/plain', e.target.id);
e.dataTransfer.setData('blood-type', e.target.getAttribute('data-blood-type'));
} else if (e.target.hasAttribute('data-step')) { // Hemostasis
e.dataTransfer.setData('text/plain', e.target.textContent);
e.dataTransfer.setData('step-number', e.target.getAttribute('data-step'));
// Pass the ID of the dragged element itself
e.dataTransfer.setData('element-id', e.target.id);
}
});
draggable.addEventListener('dragend', (e) => {
// Use setTimeout to ensure this runs after drop event logic
setTimeout(() => {
// Check if draggedItem still exists before removing class
if (e.target) { // Use e.target as draggedItem might be nullified by drop
e.target.classList.remove('dragging');
}
draggedItem = null; // Clear the reference
}, 0);
});
});
dropZones.forEach(zone => {
zone.addEventListener('dragover', (e) => {
e.preventDefault(); // Necessary to allow dropping
// Add visual cue only if dropping is valid for this zone
if (draggedItem) { // Check if an item is being dragged
if ((zone.id === 'plasma-pool' && draggedItem.hasAttribute('data-info')) ||
(zone.id === 'transfusion-drop-zone' && draggedItem.hasAttribute('data-blood-type')) ||
(zone.id.startsWith('step-target-') && draggedItem.hasAttribute('data-step')))
{
zone.classList.add('drop-zone-hover');
}
}
});
zone.addEventListener('dragleave', (e) => {
zone.classList.remove('drop-zone-hover');
});
zone.addEventListener('drop', (e) => {
e.preventDefault();
zone.classList.remove('drop-zone-hover');
if (!draggedItem) {
console.log("Drop event fired but draggedItem is null.");
return; // Exit if no item is being dragged (might happen on edge cases)
}
// --- Component Builder Logic ---
if (zone.id === 'plasma-pool' && draggedItem.hasAttribute('data-info')) {
const info = e.dataTransfer.getData('info');
const newItem = draggedItem.cloneNode(true); // Clone node is correct here
newItem.classList.remove('draggable', 'dragging');
newItem.classList.add('m-1', 'inline-block', 'cursor-pointer');
newItem.removeAttribute('id'); // Avoid duplicate IDs on clones
newItem.removeAttribute('draggable');
newItem.onclick = () => { document.getElementById('info-text').textContent = info; };
zone.appendChild(newItem);
document.getElementById('info-text').textContent = 'Component added! Click it to see info.';
}
// --- Transfusion Logic ---
else if (zone.id === 'transfusion-drop-zone' && draggedItem.hasAttribute('data-blood-type')) {
const donorType = e.dataTransfer.getData('blood-type');
const patientType = document.getElementById('patient-blood-type').textContent;
checkTransfusionCompatibility(patientType, donorType);
// Note: Original draggable item remains in the blood bank.
}
// --- Hemostasis Logic (Corrected) ---
else if (zone.classList.contains('drop-zone') && zone.id.startsWith('step-target-') && draggedItem.hasAttribute('data-step')) {
// Ensure the dragged item originated from the source pool (or another target pool if allowing reordering)
// For simplicity, we only allow dragging from the source pool here.
if (!draggedItem.closest('.step-source')) {
console.log("Attempted to drop item not from source pool.");
// draggedItem = null; // Clear reference if drop is invalid
return; // Prevent dropping items dragged from within the target area
}
const sourcePool = document.getElementById('hemostasis-steps-source');
const existingItemInZone = zone.querySelector('.step');
// If replacing an existing step in the target zone
if (existingItemInZone) {
// Move the existing item back to the source pool
sourcePool.appendChild(existingItemInZone);
// Make it draggable again and apply source styling
existingItemInZone.draggable = true;
existingItemInZone.classList.add('draggable');
existingItemInZone.classList.remove('bg-gray-200'); // Remove target styling
existingItemInZone.classList.add('bg-indigo-100', 'border-indigo-300'); // Re-apply source styling (adjust if needed)
existingItemInZone.style.cursor = 'grab';
}
// Clear the target zone's text content (keeping the number prefix)
zone.innerHTML = `${zone.getAttribute('data-order')}. `;
// *** Move the ACTUAL dragged item (not a clone) ***
zone.appendChild(draggedItem);
// Style the moved item for the target zone
draggedItem.classList.remove('draggable', 'dragging'); // Make it non-draggable in target
draggedItem.classList.add('bg-gray-200'); // Apply target styling
draggedItem.style.cursor = 'default';
draggedItem.draggable = false;
// No need to explicitly removeChild from parent, appendChild handles the move.
}
// It's generally safer to nullify draggedItem in dragend
// draggedItem = null;
});
});
}
// --- Blood Typing Lab Logic ---
function addSerum(sampleId, serumType, actualBloodType) {
const well = document.getElementById(`${sampleId}-${serumType}`);
let clumps = false;
const aboType = actualBloodType.slice(0, -1);
const rhType = actualBloodType.slice(-1);
if (serumType === 'anti-a' && (aboType.includes('A'))) clumps = true;
else if (serumType === 'anti-b' && (aboType.includes('B'))) clumps = true;
else if (serumType === 'anti-rh' && (rhType === '+')) clumps = true;
well.classList.remove('not-clumped', 'clumped');
well.classList.add(clumps ? 'clumped' : 'not-clumped');
well.setAttribute('data-clumped', clumps.toString());
}
function checkType(sampleId, correctType) {
const guess = document.getElementById(`${sampleId}-guess`).value;
const feedback = document.getElementById(`${sampleId}-feedback`);
const actualTypeSpan = document.querySelector(`#${sampleId}-anti-a`).closest('.border').querySelector('.sample-type');
if (guess === correctType) {
feedback.textContent = 'Correct!';
feedback.className = 'text-center mt-2 text-sm font-semibold text-green-600';
actualTypeSpan.textContent = correctType;
} else if (guess === "") {
feedback.textContent = 'Please make a selection.';
feedback.className = 'text-center mt-2 text-sm font-semibold text-gray-600';
} else {
feedback.textContent = `no silly, try again`;
feedback.className = 'text-center mt-2 text-sm font-semibold text-red-600';
}
}
// --- Inheritance Predictor Logic ---
function calculateInheritance() {
const p1_abo = document.getElementById('p1-abo').value;
const p1_rh = document.getElementById('p1-rh').value;
const p2_abo = document.getElementById('p2-abo').value;
const p2_rh = document.getElementById('p2-rh').value;
const possibleABO = new Set();
const possibleRh = new Set();
const p1_can_pass_A = p1_abo.includes('A');
const p1_can_pass_B = p1_abo.includes('B');
let p1_can_pass_O = p1_abo === 'A' || p1_abo === 'B' || p1_abo === 'O';
if (p1_abo === 'AB') p1_can_pass_O = false;
if (p1_abo === 'O') {p1_can_pass_A = false; p1_can_pass_B = false;}
const p2_can_pass_A = p2_abo.includes('A');
const p2_can_pass_B = p2_abo.includes('B');
let p2_can_pass_O = p2_abo === 'A' || p2_abo === 'B' || p2_abo === 'O';
if (p2_abo === 'AB') p2_can_pass_O = false;
if (p2_abo === 'O') {p2_can_pass_A = false; p2_can_pass_B = false;}
if ((p1_can_pass_A && p2_can_pass_A) || (p1_can_pass_A && p2_can_pass_O) || (p1_can_pass_O && p2_can_pass_A)) possibleABO.add('A');
if ((p1_can_pass_B && p2_can_pass_B) || (p1_can_pass_B && p2_can_pass_O) || (p1_can_pass_O && p2_can_pass_B)) possibleABO.add('B');
if ((p1_can_pass_A && p2_can_pass_B) || (p1_can_pass_B && p2_can_pass_A)) possibleABO.add('AB');
if (p1_can_pass_O && p2_can_pass_O) possibleABO.add('O');
const p1_can_pass_pos = p1_rh === '+';
const p1_can_pass_neg = true;
const p2_can_pass_pos = p2_rh === '+';
const p2_can_pass_neg = true;
if (p1_can_pass_pos || p2_can_pass_pos) possibleRh.add('+');
// Only possible to be Rh- if both parents can pass the negative allele
// (which is true if parent is Rh- or assumed Rh+/- if parent is Rh+)
// Simplified: child can be Rh- only if *both* parents are Rh- OR if *both* parents are Rh+ (assumed +/-)
// Let's stick to the simpler: Can be Rh- if both parents *can* pass neg (which is always true unless we model ++ explicitly)
if (p1_can_pass_neg && p2_can_pass_neg) { // This condition is always true with current model
// More accurate check: Child is Rh- *only if* both parents pass '-'
// This happens if P1 is '-' and P2 is '-', OR P1 is +/- and P2 is '-', OR P1 is '-' and P2 is +/-, OR P1 is +/- and P2 is +/-
// Simplified: Can be Rh- if *at least one* parent is Rh-, OR if *both* are Rh+ (assuming +/- genotype)
// Let's refine: Can be Rh- if both parents are Rh- OR if one is Rh- and one is Rh+ OR if both are Rh+
// Safest simple rule: Can be Rh- unless *both* parents are Rh+ (and we assume ++, which isn't right).
// Let's use: Can be Rh- if *at least one* parent is Rh-. If both are Rh+, child *can* still be Rh- but let's simplify for this model.
// If both parents are Rh+, the child *can* be Rh-, but it's less likely. Let's include it.
possibleRh.add('-'); // Allow possibility of Rh- unless explicitly ++ which we don't model.
}
// If one parent is Rh- and the other is Rh+, Rh- is possible.
// If both parents are Rh-, Rh- is the only possibility.
const resultsText = document.getElementById('possible-types-text');
if (possibleABO.size === 0 || possibleRh.size === 0) {
resultsText.textContent = "Error calculating possibilities.";
return;
}
let fullTypes = [];
possibleABO.forEach(abo => {
possibleRh.forEach(rh => {
fullTypes.push(abo + rh);
});
});
resultsText.innerHTML = `Possible ABO types: <strong class="text-green-900">${[...possibleABO].join(', ')}</strong><br>
Possible Rh types: <strong class="text-green-900">${[...possibleRh].join(', ')}</strong><br>
Possible full blood types: <strong class="text-green-900">${fullTypes.join(', ')}</strong>`;
}
// --- Transfusion Simulation Logic ---
const bloodTypes = ['A+', 'A-', 'B+', 'B-', 'AB+', 'AB-', 'O+', 'O-'];
function populateBloodBank() {
const bank = document.getElementById('blood-bank');
bank.innerHTML = '';
bloodTypes.forEach(type => {
const bag = document.createElement('div');
// Use a unique ID for each bag based on type
bag.id = `bag-${type.replace(/[+-]/g, m => ({'+': 'pos', '-': 'neg'})[m])}`;
bag.className = 'draggable step p-3 bg-red-200 border border-red-400 rounded-lg shadow text-center font-bold text-red-800'; // Added 'step' class for consistency if needed
bag.draggable = true;
bag.textContent = type;
bag.setAttribute('data-blood-type', type);
bank.appendChild(bag);
});
setupDragAndDrop(); // Important to re-attach listeners after modifying DOM
}
function changePatientType() {
const newType = bloodTypes[Math.floor(Math.random() * bloodTypes.length)];
document.getElementById('patient-blood-type').textContent = newType;
document.getElementById('transfusion-feedback').textContent = '\u00A0';
document.getElementById('transfusion-drop-zone').innerHTML = 'Drop Bag Here';
document.getElementById('transfusion-drop-zone').className = 'drop-zone mt-4 p-4 min-h-[80px] bg-blue-50 border-blue-300';
// No need to repopulate bank, bags are always the same
// populateBloodBank();
}
function checkTransfusionCompatibility(patientType, donorType) {
const feedbackEl = document.getElementById('transfusion-feedback');
const dropZoneEl = document.getElementById('transfusion-drop-zone');
let compatible = false;
const patientABO = patientType.replace(/[+-]/, '');
const patientRh = patientType.includes('+');
const donorABO = donorType.replace(/[+-]/, '');
const donorRh = donorType.includes('+');
let aboCompatible = false;
if (patientABO === 'AB') aboCompatible = true;
else if (patientABO === 'A') aboCompatible = (donorABO === 'A' || donorABO === 'O');
else if (patientABO === 'B') aboCompatible = (donorABO === 'B' || donorABO === 'O');
else if (patientABO === 'O') aboCompatible = (donorABO === 'O');
let rhCompatible = patientRh || !donorRh;
compatible = aboCompatible && rhCompatible;
dropZoneEl.textContent = `Dropped: ${donorType}`;
if (compatible) {
feedbackEl.textContent = 'Safe Transfusion!';
feedbackEl.className = 'mt-2 font-semibold h-8 text-green-600';
dropZoneEl.className = 'drop-zone mt-4 p-4 min-h-[80px] bg-green-100 border-green-400 correct-drop';
} else {
feedbackEl.textContent = `no silly, try again`;
feedbackEl.className = 'mt-2 font-semibold h-8 text-red-600';
dropZoneEl.className = 'drop-zone mt-4 p-4 min-h-[80px] bg-red-100 border-red-400 incorrect-drop';
}
}
// --- Hemostasis Sequence Logic ---
function checkHemostasisSequence() {
const targetZones = document.querySelectorAll('.step-target .drop-zone');
let correct = true;
let message = "Correct Sequence!";
let allFilled = true;
targetZones.forEach(zone => {
const expectedOrder = zone.getAttribute('data-order');
const droppedItem = zone.querySelector('.step');
if (droppedItem) {
const droppedOrder = droppedItem.getAttribute('data-step');
if (expectedOrder !== droppedOrder) {
correct = false;
}
} else {
allFilled = false;
correct = false; // Can't be correct if not all filled
}
});
const feedbackEl = document.getElementById('hemostasis-feedback');
const targetContainer = document.querySelector('.step-target');
if (!allFilled) {
message = "Please fill all steps.";
// correct remains false
} else if (!correct) {
message = "no silly, try again";
}
// Else: message remains "Correct Sequence!"
feedbackEl.textContent = message;
if (correct && allFilled) {
feedbackEl.className = 'mt-2 font-semibold text-center text-green-600';
targetContainer.classList.add('correct-sequence');
} else {
feedbackEl.className = 'mt-2 font-semibold text-center text-red-600';
targetContainer.classList.remove('correct-sequence');
}
}
function resetHemostasis() {
const targetZones = document.querySelectorAll('.step-target .drop-zone');
const sourcePool = document.getElementById('hemostasis-steps-source');
// Move any items currently in target zones back to the source pool
targetZones.forEach(zone => {
const stepElement = zone.querySelector('.step');
if (stepElement) {
// Reset styling and attributes before moving back
stepElement.draggable = true;
stepElement.classList.add('draggable');
stepElement.classList.remove('bg-gray-200'); // Remove target styling
stepElement.classList.add('step-source'); // Add source styling class if needed (using CSS rule now)
stepElement.style.cursor = 'grab';
sourcePool.appendChild(stepElement); // Move the actual element
}
zone.innerHTML = `${zone.getAttribute('data-order')}. `; // Reset zone text
});
// Ensure all original steps are present and correctly styled in the source pool
const originalStepsData = [
{ text: "Coagulation (Fibrin Mesh)", step: "3" },
{ text: "Vascular Spasm", step: "1" },
{ text: "Clot Retraction & Repair", step: "4" },
{ text: "Platelet Plug Formation", step: "2" }
];
const currentStepsInSource = new Map(); // Use Map to track elements
sourcePool.querySelectorAll('.step').forEach(el => currentStepsInSource.set(el.getAttribute('data-step'), el));
originalStepsData.forEach(stepInfo => {
let stepElement = currentStepsInSource.get(stepInfo.step);
if (!stepElement) {
// If an original step is missing, create and add it back
stepElement = document.createElement('div');
stepElement.setAttribute('data-step', stepInfo.step);
stepElement.textContent = stepInfo.text;
sourcePool.appendChild(stepElement);
}
// Ensure correct attributes and classes are set/reset
stepElement.id = `hemo-step-${stepInfo.step}`; // Assign unique ID
stepElement.draggable = true;
stepElement.className = 'draggable step p-2 rounded shadow cursor-grab'; // Reset classes fully
stepElement.style.cursor = 'grab';
});
// Clear feedback and visual cues
document.getElementById('hemostasis-feedback').textContent = '\u00A0';
document.querySelector('.step-target').classList.remove('correct-sequence');
// Re-setup drag/drop listeners for items now in the source pool
setupDragAndDrop();
}
// --- Quiz Logic ---
function submitQuiz() {
const questions = document.querySelectorAll('.quiz-question');
let score = 0;
let answeredCount = 0;
questions.forEach((question, index) => {
const feedbackEl = question.querySelector('.quiz-feedback');
const selected = question.querySelector(`input[name="q${index+1}"]:checked`);
if (selected) {
answeredCount++;
const isCorrect = selected.hasAttribute('data-correct');
if (isCorrect) {
score++;
feedbackEl.textContent = 'Correct!';
feedbackEl.className = 'quiz-feedback mt-2 text-sm font-semibold text-green-600';
} else {
feedbackEl.textContent = `no silly, try again`;
feedbackEl.className = 'quiz-feedback mt-2 text-sm font-semibold text-red-600';
}
} else {
feedbackEl.textContent = 'Please select an answer.';
feedbackEl.className = 'quiz-feedback mt-2 text-sm font-semibold text-gray-600';
}
});
const resultsEl = document.getElementById('quiz-results');
if (answeredCount === questions.length) {
resultsEl.textContent = `You scored ${score} out of ${questions.length}!`;
resultsEl.className = `mt-4 text-xl font-semibold ${score === questions.length ? 'text-green-600' : 'text-blue-600'}`;
} else {
resultsEl.textContent = 'Please answer all questions before submitting.';
resultsEl.className = 'mt-4 text-xl font-semibold text-red-600';
}
}
// --- Initial Setup ---
document.addEventListener('DOMContentLoaded', () => {
showPage('home');
populateBloodBank(); // Populate transfusion bags first
resetHemostasis(); // Then initialize Hemostasis (which calls setupDragAndDrop)
calculateInheritance(); // Run initial inheritance calculation
// Note: setupDragAndDrop() is called within resetHemostasis() and populateBloodBank()
});
</script>
</body>
</html>