<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>الدرس الثاني: خصائص المحاليل</title>
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<style>
/* ----------------------------------------------------------------
ملف تنسيق الدروس التعليمية - منصة تعلم بذكاء
---------------------------------------------------------------- */
/* Variables */
:root {
--bg-gradient-start: #312e81;
--bg-gradient-end: #581c87;
--text-primary: #f1f5f9;
--text-secondary: #cbd5e1;
--text-accent: #e9d5ff;
--card-bg: rgba(30, 41, 59, 0.6);
--card-border: rgba(255, 255, 255, 0.1);
--header-gradient: linear-gradient(to right, #312e81, #581c87);
--accent-purple: #a855f7;
--accent-blue: #3b82f6;
--accent-green: #22c55e;
--accent-yellow: #eab308;
--accent-red: #ef4444;
}
* {
box-sizing: border-box;
}
body {
font-family: 'Cairo', sans-serif;
background: linear-gradient(to bottom right, var(--bg-gradient-start), var(--bg-gradient-end));
color: var(--text-primary);
margin: 0;
padding: 0;
line-height: 1.6;
direction: rtl;
min-height: 100vh;
}
.lesson-container {
max-width: 900px;
margin: 0 auto;
padding: 24px;
}
.lesson-header {
background: var(--header-gradient);
border: 1px solid var(--card-border);
border-radius: 16px;
padding: 24px;
text-align: center;
margin-bottom: 32px;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3);
}
.lesson-title {
font-size: 2.25rem;
font-weight: 800;
margin: 0 0 8px 0;
background: linear-gradient(to right, #bfdbfe, #e9d5ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.lesson-subtitle {
color: var(--text-accent);
font-size: 1.125rem;
}
.lesson-section {
margin-bottom: 24px;
border-top: 1px solid var(--card-border);
padding-top: 24px;
}
.section-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 1.5rem;
font-weight: 700;
color: #fff;
margin-bottom: 16px;
}
.info-card {
background-color: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: 12px;
padding: 20px;
margin-bottom: 16px;
}
.card-purple { border-right: 4px solid var(--accent-purple); }
.card-blue { border-right: 4px solid var(--accent-blue); }
.card-green { border-right: 4px solid var(--accent-green); }
.card-red { border-right: 4px solid var(--accent-red); }
.card-yellow { border-right: 4px solid var(--accent-yellow); }
.card-title {
font-weight: 700;
margin-bottom: 8px;
display: block;
color: #fff;
}
.text-purple { color: #d8b4fe; }
.text-blue { color: #93c5fd; }
.text-green { color: #86efac; }
.text-yellow { color: #fde047; }
.text-orange { color: #fdba74; }
.lesson-list {
list-style-type: disc;
list-style-position: inside;
color: var(--text-secondary);
font-size: 0.95rem;
padding-right: 10px;
}
.lesson-list li {
margin-bottom: 6px;
}
.lesson-list li::marker {
color: var(--accent-purple);
}
.formula-box {
font-family: monospace;
background-color: rgba(0, 0, 0, 0.3);
padding: 8px 12px;
border-radius: 6px;
color: var(--accent-yellow);
direction: ltr;
display: inline-block;
margin: 4px 0;
font-size: 1.1rem;
}
.formula-box-large {
font-family: monospace;
background-color: rgba(0, 0, 0, 0.3);
padding: 12px 16px;
border-radius: 8px;
color: var(--accent-yellow);
direction: ltr;
display: block;
text-align: center;
margin: 12px auto;
font-size: 1.25rem;
max-width: 400px;
}
.lesson-table-wrapper {
overflow-x: auto;
border: 1px solid var(--card-border);
border-radius: 8px;
background-color: rgba(0, 0, 0, 0.2);
margin: 16px 0;
}
.lesson-table {
width: 100%;
text-align: center;
border-collapse: collapse;
color: var(--text-secondary);
font-size: 0.9rem;
}
.lesson-table thead {
background-color: rgba(255, 255, 255, 0.1);
color: #fff;
text-transform: uppercase;
font-size: 0.85rem;
}
.lesson-table th, .lesson-table td {
padding: 12px 16px;
border-bottom: 1px solid var(--card-border);
}
.lesson-table tr:hover {
background-color: rgba(255, 255, 255, 0.05);
}
/* Simulator Styles */
.simulation-container {
background-color: rgba(15, 23, 42, 0.6);
border: 1px solid var(--card-border);
border-radius: 16px;
padding: 24px;
margin: 24px 0;
box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.2);
}
.sim-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.sim-title {
font-size: 1.25rem;
font-weight: 700;
color: #fff;
}
.reset-btn {
padding: 8px;
border-radius: 50%;
background: transparent;
border: none;
color: #94a3b8;
font-size: 1.25rem;
cursor: pointer;
transition: all 0.2s;
}
.reset-btn:hover {
background: rgba(255, 255, 255, 0.1);
color: #fff;
}
.canvas-container {
position: relative;
display: flex;
justify-content: center;
margin: 16px 0;
background: rgba(0, 0, 0, 0.2);
border-radius: 8px;
padding: 16px;
}
canvas {
max-width: 100%;
border-radius: 8px;
}
.controls-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--card-border);
}
.control-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.control-label {
font-weight: 600;
color: var(--text-secondary);
text-align: center;
font-size: 0.9rem;
}
.slider-container {
display: flex;
align-items: center;
gap: 8px;
}
input[type="range"] {
flex: 1;
height: 8px;
background: #334155;
border-radius: 4px;
outline: none;
-webkit-appearance: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 18px;
height: 18px;
background: #64748b;
border-radius: 50%;
cursor: pointer;
transition: background 0.2s;
}
input[type="range"]::-webkit-slider-thumb:hover {
background: #94a3b8;
}
input[type="range"].accent-red::-webkit-slider-thumb { background: #f87171; }
input[type="range"].accent-orange::-webkit-slider-thumb { background: #fb923c; }
input[type="range"].accent-blue::-webkit-slider-thumb { background: #60a5fa; }
input[type="range"].accent-teal::-webkit-slider-thumb { background: #2dd4bf; }
.value-display {
text-align: center;
font-size: 0.85rem;
color: var(--text-secondary);
}
.value-mono {
font-family: monospace;
font-weight: bold;
color: #fff;
}
.status-box {
margin-top: 16px;
padding: 12px;
border-radius: 8px;
text-align: center;
background: rgba(30, 41, 59, 0.8);
transition: all 0.3s;
}
.status-box.active {
background: rgba(34, 197, 94, 0.2);
border: 1px solid rgba(34, 197, 94, 0.3);
}
.status-text {
font-weight: bold;
color: var(--text-secondary);
}
.status-box.active .status-text {
color: #86efac;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
.btn-group {
display: flex;
gap: 4px;
padding: 4px;
background: rgba(51, 65, 85, 0.5);
border-radius: 8px;
}
.btn-option {
flex: 1;
padding: 6px 12px;
border: none;
border-radius: 6px;
background: transparent;
color: var(--text-secondary);
font-size: 0.75rem;
cursor: pointer;
transition: all 0.2s;
font-family: 'Cairo', sans-serif;
}
.btn-option:hover {
background: rgba(255, 255, 255, 0.1);
}
.btn-option.active {
color: #000;
font-weight: 600;
}
.legend {
display: flex;
justify-content: center;
gap: 24px;
margin-top: 12px;
flex-wrap: wrap;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.85rem;
color: var(--text-secondary);
}
.legend-color {
width: 16px;
height: 4px;
border-radius: 2px;
}
.legend-dot {
width: 12px;
height: 12px;
border-radius: 50%;
}
.info-text {
margin-top: 16px;
padding: 16px;
background: rgba(30, 41, 59, 0.6);
border-radius: 8px;
font-size: 0.9rem;
color: var(--text-secondary);
text-align: center;
line-height: 1.8;
}
.comparison-table {
width: 100%;
margin-top: 8px;
font-size: 0.85rem;
}
.comparison-table th,
.comparison-table td {
padding: 8px;
text-align: center;
border: 1px solid var(--card-border);
}
.comparison-table th {
background: rgba(255, 255, 255, 0.05);
color: #fff;
}
.highlight {
background: rgba(168, 85, 247, 0.2);
padding: 2px 6px;
border-radius: 4px;
color: #fff;
}
/* Specific simulator addons */
.gauge-container {
position: absolute;
top: 16px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.4);
padding: 12px;
border-radius: 50%;
width: 120px;
height: 120px;
}
.beaker-labels {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: space-around;
pointer-events: none;
}
.beaker-info {
text-align: center;
margin-top: 20px;
}
.frost-indicator {
position: absolute;
font-size: 2rem;
transition: all 0.3s;
}
.arrow-indicator {
display: inline-flex;
align-items: center;
justify-content: center;
margin: 0 4px;
}
/* Scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #1e1b4b;
}
::-webkit-scrollbar-thumb {
background: #4f46e5;
border-radius: 4px;
}
@media (max-width: 640px) {
.lesson-title { font-size: 1.5rem; }
.section-title { font-size: 1.25rem; }
.controls-grid { grid-template-columns: 1fr; }
}
</style>
<base target="_blank">
</head>
<body>
<div class="lesson-container">
<div class="lesson-header">
<h1 class="lesson-title">الدرس الثاني: خصائص المحاليل</h1>
<div class="lesson-subtitle">الخصائص الجامعة للمحاليل (Colligative Properties)</div>
</div>
<!-- Section 1 -->
<div class="lesson-section">
<h2 class="section-title">١. الخصائص الجامعة للمحاليل</h2>
<div class="info-card card-purple">
<span class="card-title text-purple">التعريف:</span>
<ul class="lesson-list">
<li>خصائص فيزيائية للمحاليل تعتمد على <strong class="highlight">عدد جسيمات المذاب</strong> وليس على طبيعتها الكيميائية.</li>
<li>أي أنها تعتمد على التركيز المولالي للمذاب.</li>
</ul>
</div>
<div class="info-card">
<span class="card-title">الخصائص الجامعة الأربع الرئيسية:</span>
<ol class="lesson-list" style="list-style-type: decimal;">
<li>الانخفاض في الضغط البخاري</li>
<li>الارتفاع في درجة الغليان</li>
<li>الانخفاض في درجة التجمد</li>
<li>الضغط الأسموزي</li>
</ol>
</div>
</div>
<!-- Section 2 -->
<div class="lesson-section">
<h2 class="section-title">٢. الانخفاض في الضغط البخاري (Vapor Pressure Lowering)</h2>
<div class="info-card card-blue">
<span class="card-title text-blue">التفسير العلمي:</span>
<ul class="lesson-list">
<li>عند إضافة مذاب غير متطاير إلى مذيب، تحتل جسيمات المذاب مواقع على سطح السائل.</li>
<li>تقل عدد جزيئات المذيب القادرة على التبخر.</li>
<li>يؤدي ذلك إلى انخفاض الضغط البخاري للمحلول مقارنة بالمذيب النقي.</li>
</ul>
<p style="margin-top: 12px; color: var(--text-secondary);">
<strong style="color: #fff;">العلاقة:</strong> كلما زاد تركيز المذاب، زاد انخفاض الضغط البخاري. المحاليل المركزة لها ضغط بخاري أقل من المحاليل المخففة.
</p>
</div>
<!-- Vapor Pressure Graph Simulator -->
<div id="vapor-pressure-sim"></div>
</div>
<!-- Section 3 -->
<div class="lesson-section">
<h2 class="section-title">٣. الارتفاع في درجة الغليان (Boiling Point Elevation)</h2>
<div class="info-card card-green">
<span class="card-title text-green">التفسير العلمي:</span>
<ul class="lesson-list">
<li>يغلي السائل عندما يساوي ضغطه البخاري الضغط الجوي.</li>
<li>بسبب انخفاض الضغط البخاري للمحلول، يحتاج إلى درجة حرارة أعلى ليصل ضغطه البخاري إلى الضغط الجوي.</li>
</ul>
<span class="card-title text-green" style="margin-top: 16px;">العلاقة الرياضية:</span>
<div class="formula-box-large">ΔT<sub>b</sub> = K<sub>b</sub> × m × i</div>
<p style="color: var(--text-secondary); font-size: 0.9rem;">حيث:</p>
<ul class="lesson-list" style="font-size: 0.9rem;">
<li><span class="formula-box">ΔT<sub>b</sub></span>: الارتفاع في درجة الغليان</li>
<li><span class="formula-box">K<sub>b</sub></span>: ثابت الارتفاع في درجة الغليان للمذيب</li>
<li><span class="formula-box">m</span>: التركيز المولالي (مول/كجم)</li>
<li><span class="formula-box">i</span>: معامل فانت هوف (عدد الجسيمات الناتجة من المذاب)</li>
</ul>
</div>
<div class="info-card">
<span class="card-title">القوانين الأساسية للتركيز:</span>
<div class="formula-box-large" style="font-size: 1rem; margin: 8px auto;">عدد المولات (mol) = كتلة المذاب (g) / الكتلة المولية (g/mol)</div>
<div class="formula-box-large" style="font-size: 1rem; margin: 8px auto;">التركيز المولالي (m) = عدد مولات المذاب (mol) / كتلة المذيب (kg)</div>
</div>
<div class="info-card">
<span class="card-title">شرح معامل فانت هوف (i)</span>
<p style="color: var(--text-secondary); font-size: 0.9rem; margin-bottom: 16px;">
يمثل معامل فانت هوف عدد الجسيمات (أيونات أو جزيئات) الفعلية التي تنتج من ذوبان وحدة صيغة واحدة من المذاب في المذيب.
</p>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px;">
<div class="info-card" style="background: rgba(0,0,0,0.2); margin: 0;">
<h4 style="color: #fff; margin-bottom: 8px;">المواد غير المتأينة (Non-electrolytes)</h4>
<p style="font-size: 0.8rem; color: #94a3b8; margin-bottom: 8px;">تبقى على شكل جزيئات ولا تتفكك.</p>
<div class="formula-box">i = 1</div>
<p style="font-size: 0.85rem; color: var(--text-secondary); margin-top: 8px;">
<strong>أمثلة:</strong> السكر (C₁₂H₂₂O₁₁)، اليوريا (CO(NH₂)₂)
</p>
</div>
<div class="info-card" style="background: rgba(0,0,0,0.2); margin: 0;">
<h4 style="color: #fff; margin-bottom: 8px;">المواد المتأينة (Electrolytes)</h4>
<p style="font-size: 0.8rem; color: #94a3b8; margin-bottom: 8px;">تتفكك إلى أيونات.</p>
<div class="formula-box">i > 1</div>
<p style="font-size: 0.85rem; color: var(--text-secondary); margin-top: 8px; direction: ltr; text-align: right;">
NaCl → Na⁺ + Cl⁻ (i=2)<br>
CaCl₂ → Ca²⁺ + 2Cl⁻ (i=3)
</p>
</div>
</div>
<div class="info-card card-yellow" style="margin-top: 16px; margin-bottom: 0;">
<p style="font-size: 0.85rem; color: #fde047;">
<strong>الأهمية:</strong> كلما زادت قيمة 'i'، زاد عدد الجسيمات في المحلول، وبالتالي زاد التأثير على الخصائص الجامعة.
</p>
</div>
</div>
<!-- Boiling Point Constants Table -->
<div id="boiling-constants-table"></div>
<!-- Examples -->
<div class="info-card card-green" style="margin-top: 24px;">
<h4 style="color: #86efac; margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
<span>📝</span> أمثلة حسابية
</h4>
<div style="margin-bottom: 24px;">
<p style="color: var(--text-secondary); margin-bottom: 12px; font-size: 0.9rem;">
<strong>مثال 1 (مذاب لا إلكتروليتي):</strong> احسب درجة غليان محلول محضر بإذابة 34.2 جرام من السكر (السكروز، C₁₂H₂₂O₁₁, الكتلة المولية = 342 g/mol) في 200 جرام من الماء. (K<sub>b</sub> للماء = 0.512 °C·kg/mol)
</p>
<div style="background: rgba(0,0,0,0.3); padding: 12px; border-radius: 6px; font-family: monospace; font-size: 0.85rem; color: #86efac; direction: ltr; text-align: left; line-height: 1.6;">
1. Moles of solute = 34.2 g / 342 g/mol = 0.1 mol<br>
2. Mass of solvent (kg) = 200 g / 1000 = 0.2 kg<br>
3. Molality (m) = 0.1 mol / 0.2 kg = 0.5 m<br>
4. Van 't Hoff factor (i) = 1 (since sucrose is a non-electrolyte)<br>
5. ΔT<sub>b</sub> = K<sub>b</sub> × m × i = 0.512 × 0.5 × 1 = 0.256 °C<br>
6. New Boiling Point = 100 °C + 0.256 °C = <strong>100.256 °C</strong>
</div>
</div>
<div>
<p style="color: var(--text-secondary); margin-bottom: 12px; font-size: 0.9rem;">
<strong>مثال 2 (مذاب إلكتروليتي):</strong> ما هي درجة غليان محلول يحتوي على 11.7 جرام من ملح الطعام (NaCl، الكتلة المولية = 58.5 g/mol) مذابة في 500 جرام من الماء؟
</p>
<div style="background: rgba(0,0,0,0.3); padding: 12px; border-radius: 6px; font-family: monospace; font-size: 0.85rem; color: #86efac; direction: ltr; text-align: left; line-height: 1.6;">
1. Moles of solute = 11.7 g / 58.5 g/mol = 0.2 mol<br>
2. Mass of solvent (kg) = 500 g / 1000 = 0.5 kg<br>
3. Molality (m) = 0.2 mol / 0.5 kg = 0.4 m<br>
4. Van 't Hoff factor (i) = 2 (since NaCl → Na⁺ + Cl⁻)<br>
5. ΔT<sub>b</sub> = K<sub>b</sub> × m × i = 0.512 × 0.4 × 2 = 0.4096 °C<br>
6. New Boiling Point = 100 °C + 0.4096 °C ≈ <strong>100.41 °C</strong>
</div>
</div>
</div>
<!-- Boiling Point Elevation Simulator -->
<div id="boiling-point-sim"></div>
</div>
<!-- Section 4 -->
<div class="lesson-section">
<h2 class="section-title">٤. الانخفاض في درجة التجمد (Freezing Point Depression)</h2>
<div class="info-card card-blue">
<span class="card-title text-blue">التفسير العلمي:</span>
<ul class="lesson-list">
<li>تعيق جسيمات المذاب انتظام جسيمات المذيب في الشبكة البلورية.</li>
<li>يحتاج المذيب إلى درجة حرارة أقل لتتجمد جسيماته.</li>
</ul>
<span class="card-title text-blue" style="margin-top: 16px;">العلاقة الرياضية:</span>
<div class="formula-box-large">ΔT<sub>f</sub> = K<sub>f</sub> × m × i</div>
<p style="color: var(--text-secondary); font-size: 0.9rem;">حيث:</p>
<ul class="lesson-list" style="font-size: 0.9rem;">
<li><span class="formula-box">ΔT<sub>f</sub></span>: الانخفاض في درجة التجمد</li>
<li><span class="formula-box">K<sub>f</sub></span>: ثابت الانخفاض في درجة التجمد للمذيب</li>
</ul>
<span class="card-title text-blue" style="margin-top: 16px;">التطبيقات العملية:</span>
<ul class="lesson-list">
<li>إزالة الجليد من الطرق: برش الملح (NaCl) أو كلوريد الكالسيوم (CaCl₂).</li>
<li>مبردات السيارات: إضافة الإيثيلين جلايكول لمنع تجمد الماء.</li>
</ul>
</div>
<!-- Freezing Point Constants Table -->
<div id="freezing-constants-table"></div>
<!-- Freezing Point Depression Simulator -->
<div id="freezing-point-sim"></div>
<!-- Examples -->
<div class="info-card card-green" style="margin-top: 24px;">
<h4 style="color: #86efac; margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
<span>📝</span> أمثلة حسابية
</h4>
<div style="margin-bottom: 24px;">
<p style="color: var(--text-secondary); margin-bottom: 12px; font-size: 0.9rem;">
<strong>مثال 1 (مذاب لا إلكتروليتي):</strong> احسب درجة تجمد محلول محضر بإذابة 18 جرام من الجلوكوز (C₆H₁₂O₆، الكتلة المولية = 180 g/mol) في 250 جرام من الماء. (K<sub>f</sub> للماء = 1.86 °C·kg/mol)
</p>
<div style="background: rgba(0,0,0,0.3); padding: 12px; border-radius: 6px; font-family: monospace; font-size: 0.85rem; color: #86efac; direction: ltr; text-align: left; line-height: 1.6;">
1. Moles of solute = 18 g / 180 g/mol = 0.1 mol<br>
2. Mass of solvent (kg) = 250 g / 1000 = 0.25 kg<br>
3. Molality (m) = 0.1 mol / 0.25 kg = 0.4 m<br>
4. Van 't Hoff factor (i) = 1 (non-electrolyte)<br>
5. ΔT<sub>f</sub> = K<sub>f</sub> × m × i = 1.86 × 0.4 × 1 = 0.744 °C<br>
6. New Freezing Point = 0 °C - 0.744 °C = <strong>-0.744 °C</strong>
</div>
</div>
<div>
<p style="color: var(--text-secondary); margin-bottom: 12px; font-size: 0.9rem;">
<strong>مثال 2 (مذاب إلكتروليتي):</strong> احسب درجة تجمد محلول يحتوي على 11.1 جرام من كلوريد الكالسيوم (CaCl₂، الكتلة المولية = 111 g/mol) مذابة في 500 جرام من الماء.
</p>
<div style="background: rgba(0,0,0,0.3); padding: 12px; border-radius: 6px; font-family: monospace; font-size: 0.85rem; color: #86efac; direction: ltr; text-align: left; line-height: 1.6;">
1. Moles of solute = 11.1 g / 111 g/mol = 0.1 mol<br>
2. Mass of solvent (kg) = 500 g / 1000 = 0.5 kg<br>
3. Molality (m) = 0.1 mol / 0.5 kg = 0.2 m<br>
4. Van 't Hoff factor (i) = 3 (since CaCl₂ → Ca²⁺ + 2Cl⁻)<br>
5. ΔT<sub>f</sub> = K<sub>f</sub> × m × i = 1.86 × 0.2 × 3 = 1.116 °C<br>
6. New Freezing Point = 0 °C - 1.116 °C = <strong>-1.116 °C</strong>
</div>
</div>
</div>
</div>
<!-- Section 5 -->
<div class="lesson-section">
<h2 class="section-title">٥. الضغط الأسموزي (Osmotic Pressure)</h2>
<div class="info-card card-purple">
<span class="card-title text-purple">التفسير العلمي:</span>
<ul class="lesson-list">
<li><strong class="highlight">الأسموزية:</strong> انتشار المذيب عبر غشاء شبه منفذ من المنطقة الأقل تركيزاً إلى المنطقة الأعلى تركيزاً.</li>
<li><strong class="highlight">الضغط الأسموزي:</strong> الضغط اللازم لمنع حدوث الأسموزية.</li>
</ul>
<span class="card-title text-purple" style="margin-top: 16px;">أهميته الحيوية:</span>
<ul class="lesson-list">
<li>امتصاص الماء في النباتات.</li>
<li>العمليات الحيوية في خلايا الجسم.</li>
</ul>
</div>
<!-- Osmosis Simulator -->
<div id="osmosis-sim"></div>
</div>
<!-- Section 6 -->
<div class="lesson-section">
<h2 class="section-title">٦. تأثير نوع المذاب (متأين vs غير متأين)</h2>
<div class="info-card">
<span class="card-title">مقارنة مهمة:</span>
<ul class="lesson-list">
<li><strong class="highlight" style="background: rgba(239, 68, 68, 0.3);">المادة المتأينة (مثل NaCl):</strong> تتفكك إلى أيونات ← عدد جسيمات أكبر ← تأثير أكبر على الخصائص الجامعة.</li>
<li><strong class="highlight" style="background: rgba(34, 197, 94, 0.3);">المادة غير المتأينة (مثل سكر الجلوكوز):</strong> تبقى كجزيئات ← عدد جسيمات أقل ← تأثير أقل.</li>
</ul>
<div class="info-card card-green" style="margin-top: 16px;">
<h4 style="color: #86efac; margin-bottom: 12px; display: flex; align-items: center; gap: 8px;">
<span>📝</span> مثال توضيحي
</h4>
<div style="background: rgba(0,0,0,0.3); padding: 12px; border-radius: 6px; font-family: monospace; font-size: 0.9rem; color: #86efac; direction: ltr;">
<p style="margin-bottom: 8px;">محلول NaCl (0.1 m):<br>i = 2 → ΔT<sub>b</sub> = 0.512 × 0.1 × 2 = 0.1024 °C</p>
<p>محلول C₆H₁₂O₆ (0.1 m):<br>i = 1 → ΔT<sub>b</sub> = 0.512 × 0.1 × 1 = 0.0512 °C</p>
</div>
</div>
</div>
</div>
<!-- Section 7 -->
<div class="lesson-section">
<h2 class="section-title">٧. التطبيقات العملية في الحياة اليومية:</h2>
<div class="info-card">
<ol class="lesson-list" style="list-style-type: decimal;">
<li style="margin-bottom: 12px;"><strong>طهي الطعام في المرتفعات:</strong> ينضج الطعام بدرجة حرارة أقل بسبب انخفاض درجة غليان الماء.</li>
<li style="margin-bottom: 12px;"><strong>إزالة الجليد من الطرقات:</strong> يمنع الملح تكون الجليد بانخفاضه درجة تجمد الماء.</li>
<li style="margin-bottom: 12px;"><strong>صناعة المثلجات:</strong> إضافة الملح إلى الثلج يخفض درجة تجمده فيمكنه امتصاص حرارة أكثر.</li>
<li style="margin-bottom: 12px;"><strong>الطبخ بسرعة:</strong> إضافة الملح إلى الماء يرفع قليلاً من درجة غليانه.</li>
</ol>
</div>
</div>
<!-- Summary Table -->
<div class="lesson-section">
<h2 class="section-title">📝 ملخص المعادلات الأساسية:</h2>
<div class="lesson-table-wrapper">
<table class="lesson-table">
<thead>
<tr>
<th style="width: 40%;">الخاصية</th>
<th>المعادلة</th>
</tr>
</thead>
<tbody>
<tr>
<td style="font-weight: bold;">الارتفاع في درجة الغليان</td>
<td class="formula-box" style="background: transparent; border: none; font-size: 1.2rem;">ΔT<sub>b</sub> = K<sub>b</sub> × m × i</td>
</tr>
<tr>
<td style="font-weight: bold;">الانخفاض في درجة التجمد</td>
<td class="formula-box" style="background: transparent; border: none; font-size: 1.2rem;">ΔT<sub>f</sub> = K<sub>f</sub> × m × i</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Review Questions -->
<div class="lesson-section">
<div class="info-card card-yellow">
<h2 style="color: #fde047; margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
<span>🔍</span> أسئلة مراجعة مهمة
</h2>
<div style="color: var(--text-secondary); line-height: 2;">
<p>1. لماذا يغلي محلول الملح في الماء عند درجة حرارة أعلى من الماء النقي؟</p>
<p>2. كيف تفسر أن إضافة الملح إلى الثلج تسبب في انصهاره؟</p>
<p>3. ما الفرق في تأثير كل من NaCl وC₆H₁₂O₆ على الخصائص الجامعة للمحاليل؟</p>
<p>4. كيف يتم استخدام الظاهرة الأسموزية في تنقية المياه (الأسموزية العكسية)؟</p>
</div>
</div>
</div>
<!-- Study Tips -->
<div class="lesson-section">
<div class="info-card" style="border-left: 4px solid var(--accent-blue);">
<h2 style="color: #93c5fd; margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
<span>🎯</span> نصائح للدراسة
</h2>
<div style="color: var(--text-secondary); line-height: 2; font-size: 0.95rem;">
<p><strong style="color: #fff;">١. ارسم مخطط مقارن:</strong> المذيب النقي ← ضغط بخاري عالي | المحلول ← ضغط بخاري منخفض ← يحتاج حرارة أعلى ليغلي.</p>
<div style="margin: 12px 0;">
<h3 style="color: #fff; margin-bottom: 8px;">٢. استخدم جدول المقارنة:</h3>
<div class="lesson-table-wrapper" style="max-width: 400px;">
<table class="comparison-table">
<thead>
<tr>
<th>الخاصية</th>
<th>المذيب النقي</th>
<th>المحلول</th>
</tr>
</thead>
<tbody>
<tr>
<td>درجة الغليان</td>
<td>أقل</td>
<td>أعلى</td>
</tr>
<tr>
<td>درجة التجمد</td>
<td>أعلى</td>
<td>أقل</td>
</tr>
<tr>
<td>الضغط البخاري</td>
<td>أعلى</td>
<td>أقل</td>
</tr>
</tbody>
</table>
</div>
</div>
<p><strong style="color: #fff;">٣. تدرّب على تمييز نوع المذاب:</strong> متأين (NaCl, CaCl₂) ← i > 1 ← تأثير أكبر | غير متأين (سكر) ← i = 1 ← تأثير أقل.</p>
<div style="margin: 12px 0;">
<h3 style="color: #fff; margin-bottom: 8px;">٤. نصائح لحل المسائل:</h3>
<ol class="lesson-list" style="list-style-type: decimal; margin-right: 20px;">
<li>اكتب المعطيات والمطلوب.</li>
<li>اختر القانون المناسب.</li>
<li>تأكد من الوحدات (خاصة درجة الحرارة بالكلفن للمسائل التي لا تستخدم ΔT).</li>
<li>تحقق من معامل فانت هوف (i).</li>
</ol>
</div>
<div class="info-card card-yellow" style="margin: 16px 0 0 0;">
<h3 style="color: #fde047; margin-bottom: 8px;">⚡ نصائح سريعة للحفظ:</h3>
<ul class="lesson-list">
<li>الضغط البخاري ← <strong style="color: #fff;">يقل</strong> في المحاليل.</li>
<li>درجة الغليان ← <strong style="color: #fff;">تزيد</strong> في المحاليل.</li>
<li>درجة التجمد ← <strong style="color: #fff;">تقل</strong> في المحاليل.</li>
<li>المحاليل المركزة ← تأثير أكبر على الخصائص.</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<script>
/* ----------------------------------------------------------------
محاكاة الانخفاض في الضغط البخاري (Vapor Pressure Lowering)
---------------------------------------------------------------- */
(function() {
const container = document.getElementById('vapor-pressure-sim');
if (!container) return;
const width = 450;
const height = 350;
const padding = { top: 20, right: 30, bottom: 50, left: 60 };
const chartWidth = width - padding.left - padding.right;
const chartHeight = height - padding.top - padding.bottom;
const minTemp = 20;
const maxTemp = 120;
const maxPressure = 2.5;
let soluteConcentration = 0.1;
const A = 965000;
const B = 5143;
function getVaporPressure(tempC) {
const tempK = tempC + 273.15;
return A * Math.exp(-B / tempK);
}
function getX(temp) {
return padding.left + ((temp - minTemp) / (maxTemp - minTemp)) * chartWidth;
}
function getY(pressure) {
return padding.top + chartHeight - (pressure / maxPressure) * chartHeight;
}
function generatePaths() {
let solventP = '';
let solutionP = '';
const solventMoleFraction = 1 - soluteConcentration;
for (let t = minTemp; t <= maxTemp; t++) {
const solventPressure = getVaporPressure(t);
const solutionPressure = solventPressure * solventMoleFraction;
const x = getX(t);
const solventY = getY(solventPressure);
const solutionY = getY(solutionPressure);
if (t === minTemp) {
solventP += `M ${x.toFixed(2)} ${solventY.toFixed(2)}`;
solutionP += `M ${x.toFixed(2)} ${solutionY.toFixed(2)}`;
} else {
solventP += ` L ${x.toFixed(2)} ${solventY.toFixed(2)}`;
solutionP += ` L ${x.toFixed(2)} ${solutionY.toFixed(2)}`;
}
}
return { solventPath: solventP, solutionPath: solutionP };
}
function render() {
const paths = generatePaths();
const solventPathEl = document.getElementById('vp-solvent-path');
const solutionPathEl = document.getElementById('vp-solution-path');
if (solventPathEl) solventPathEl.setAttribute('d', paths.solventPath);
if (solutionPathEl) solutionPathEl.setAttribute('d', paths.solutionPath);
}
container.innerHTML = `
<div class="simulation-container">
<h3 class="sim-title" style="text-align: center; margin-bottom: 16px;">رسم بياني: الانخفاض في الضغط البخاري</h3>
<div class="canvas-container">
<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
<line x1="${padding.left}" y1="${padding.top + chartHeight}" x2="${width - padding.right}" y2="${padding.top + chartHeight}" stroke="#6b7280" stroke-width="2"/>
<line x1="${padding.left}" y1="${padding.top + chartHeight}" x2="${padding.left}" y2="${padding.top}" stroke="#6b7280" stroke-width="2"/>
<text x="${width / 2}" y="${height - 10}" fill="#9ca3af" text-anchor="middle" font-size="12">درجة الحرارة (°C)</text>
<text x="${padding.left - 45}" y="${height / 2}" fill="#9ca3af" text-anchor="middle" transform="rotate(-90, ${padding.left - 45}, ${height/2})" font-size="12">الضغط البخاري (atm)</text>
${[0.5, 1.0, 1.5, 2.0].map(p => `
<g>
<line x1="${padding.left}" y1="${getY(p)}" x2="${width - padding.right}" y2="${getY(p)}" stroke="#475569" stroke-width="0.5" stroke-dasharray="4"/>
<text x="${padding.left - 8}" y="${getY(p) + 4}" fill="#9ca3af" text-anchor="end" font-size="10">${p.toFixed(1)}</text>
</g>
`).join('')}
${[20, 40, 60, 80, 100, 120].map(t => `
<g>
<line x1="${getX(t)}" y1="${padding.top}" x2="${getX(t)}" y2="${padding.top + chartHeight}" stroke="#475569" stroke-width="0.5" stroke-dasharray="4"/>
<text x="${getX(t)}" y="${padding.top + chartHeight + 15}" fill="#9ca3af" text-anchor="middle" font-size="10">${t}</text>
</g>
`).join('')}
<path id="vp-solvent-path" fill="none" stroke="#60a5fa" stroke-width="3"/>
<path id="vp-solution-path" fill="none" stroke="#f97316" stroke-width="3" style="transition: all 0.3s;"/>
<defs>
<linearGradient id="vpGradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#34d399"/>
<stop offset="100%" stop-color="#ef4444"/>
</linearGradient>
</defs>
</svg>
</div>
<div class="legend">
<div class="legend-item">
<div class="legend-color" style="background: #60a5fa;"></div>
<span>المذيب النقي</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #f97316;"></div>
<span>المحلول</span>
</div>
</div>
<div class="controls-grid" style="max-width: 400px; margin: 16px auto 0;">
<div class="control-group">
<label class="control-label">تركيز المذاب</label>
<input type="range" min="0" max="0.2" step="0.01" value="${soluteConcentration}"
class="accent-orange" oninput="updateVPConcentration(this.value)">
<div style="display: flex; justify-content: space-between; font-size: 0.75rem; color: #64748b; margin-top: 4px;">
<span>منخفض</span>
<span>مرتفع</span>
</div>
</div>
</div>
<div class="info-text">
حرك شريط التمرير لزيادة تركيز المذاب. لاحظ كيف ينخفض منحنى الضغط البخاري للمحلول عن منحنى المذيب النقي.
</div>
</div>
`;
window.updateVPConcentration = function(val) {
soluteConcentration = parseFloat(val);
render();
};
render();
})();
/* ----------------------------------------------------------------
جدول ثوابت الارتفاع في درجة الغليان
---------------------------------------------------------------- */
(function() {
const container = document.getElementById('boiling-constants-table');
if (!container) return;
const tableData = [
{ solvent: 'الماء', kb: 0.512, bp: 100.0 },
{ solvent: 'الإيثانول', kb: 1.22, bp: 78.5 },
{ solvent: 'البنزين', kb: 2.53, bp: 80.1 },
{ solvent: 'الكلوروفورم', kb: 3.63, bp: 61.2 },
];
container.innerHTML = `
<div class="simulation-container">
<h3 class="sim-title" style="text-align: center; margin-bottom: 16px;">
ثوابت الارتفاع المولالي لدرجة الغليان (K<sub>b</sub>) لبعض المذيبات الشائعة
</h3>
<div class="lesson-table-wrapper" style="margin: 0;">
<table class="lesson-table">
<thead>
<tr>
<th>المذيب</th>
<th>درجة الغليان (°C)</th>
<th>ثابت الارتفاع (K<sub>b</sub>) (°C·kg/mol)</th>
</tr>
</thead>
<tbody>
${tableData.map(row => `
<tr>
<td style="font-weight: bold; color: #fff;">${row.solvent}</td>
<td style="font-family: monospace;">${row.bp.toFixed(1)}</td>
<td style="font-family: monospace;">${row.kb.toFixed(2)}</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
<p style="margin-top: 12px; font-size: 0.8rem; color: #94a3b8; text-align: center;">
ملاحظة: ثابت الارتفاع (K<sub>b</sub>) هو خاصية مميزة لكل مذيب.
</p>
</div>
`;
})();
/* ----------------------------------------------------------------
محاكاة ارتفاع درجة الغليان
---------------------------------------------------------------- */
(function() {
const container = document.getElementById('boiling-point-sim');
if (!container) return;
const SOLUTES = {
sucrose: { name: 'السكر', formula: 'C₁₂H₂₂O₁₁', i: 1, color: '#f97316' },
nacl: { name: 'الملح', formula: 'NaCl', i: 2, color: '#fde047' },
};
let heatingLevel = 0;
let soluteConcentration = 0;
let soluteType = 'sucrose';
let vaporPressure = 0;
let temperature = 20;
let particles = [];
let animationId = null;
let canvas, ctx;
const width = 450;
const height = 350;
const liquidSurfaceY = height - 150;
const numSolventSurfaceSpots = 20;
const ATMOSPHERIC_PRESSURE = 100;
function initParticles() {
particles = [];
let idCounter = 0;
const surfaceSpots = Array.from({ length: numSolventSurfaceSpots }, (_, i) => i);
const numSolute = Math.floor(soluteConcentration * 1.5);
for (let i = 0; i < numSolute; i++) {
const spotIndex = Math.floor(Math.random() * surfaceSpots.length);
const spot = surfaceSpots.splice(spotIndex, 1)[0];
if (spot === undefined) break;
particles.push({
id: idCounter++,
x: (spot / (numSolventSurfaceSpots - 1)) * (width - 100) + 50,
y: liquidSurfaceY,
vx: 0, vy: 0,
phase: 'solute_surface',
radius: 6,
life: 0
});
}
for (const spot of surfaceSpots) {
particles.push({
id: idCounter++,
x: (spot / (numSolventSurfaceSpots - 1)) * (width - 100) + 50,
y: liquidSurfaceY,
vx: 0, vy: 0,
phase: 'liquid_surface',
radius: 4,
life: 0
});
}
}
function calculateBoilingPoint() {
const Kb = 0.512;
const molality = (soluteConcentration / 10) * 2;
const elevation = SOLUTES[soluteType].i * Kb * molality;
return 100 + elevation;
}
function updateSimulation() {
if (!ctx) return;
const boilingPoint = calculateBoilingPoint();
const currentTemp = 90 + heatingLevel * 1.5;
temperature = currentTemp;
ctx.clearRect(0, 0, width, height);
// Draw Beaker
ctx.strokeStyle = '#9ca3af';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(10, 50);
ctx.lineTo(10, height - 40);
ctx.quadraticCurveTo(width / 2, height - 20, width - 10, height - 40);
ctx.lineTo(width - 10, 50);
ctx.stroke();
ctx.fillStyle = "rgba(56, 189, 248, 0.2)";
ctx.fillRect(12, liquidSurfaceY, width - 24, height - liquidSurfaceY - 30);
const nextParticles = [];
let vaporCount = 0;
particles.forEach(p => {
if (p.phase === 'liquid_surface') {
p.y = liquidSurfaceY + Math.sin(p.x + Date.now() / 200) * (heatingLevel / 5);
if (Math.random() < heatingLevel * 0.001) {
nextParticles.push({ ...p, phase: 'vapor', vy: -1 - Math.random(), vx: (Math.random() - 0.5) * 2 });
} else {
nextParticles.push(p);
}
} else if (p.phase === 'solute_surface') {
p.y = liquidSurfaceY + Math.sin(p.x + Date.now() / 300) * (heatingLevel / 10);
nextParticles.push(p);
} else if (p.phase === 'vapor') {
p.x += p.vx;
p.y += p.vy;
if (p.y > liquidSurfaceY && Math.random() < 0.01) {
const spotX = (Math.round(((p.x - 50) / (width - 100)) * (numSolventSurfaceSpots - 1)) / (numSolventSurfaceSpots - 1)) * (width - 100) + 50;
const isOccupied = particles.some(sp => sp.phase !== 'vapor' && Math.abs(sp.x - spotX) < 10);
if (!isOccupied) {
nextParticles.push({ ...p, phase: 'liquid_surface', y: liquidSurfaceY, x: spotX, vx: 0, vy: 0 });
} else {
nextParticles.push(p);
}
} else if (p.y > 10 && p.x > 10 && p.x < width - 10) {
vaporCount++;
nextParticles.push(p);
}
} else if (p.phase === 'bubble') {
p.y += p.vy;
p.radius += 0.2;
if (p.life) p.life--;
if (p.y < liquidSurfaceY || (p.life && p.life <= 0)) {
for (let i = 0; i < 3; i++) {
nextParticles.push({
...p, id: p.id + 1000 + i, phase: 'vapor',
vy: -1 - Math.random(),
vx: (Math.random() - 0.5) * 2,
radius: 4
});
}
} else {
nextParticles.push(p);
}
}
});
if (currentTemp >= boilingPoint && Math.random() < heatingLevel * 0.02) {
nextParticles.push({
id: Date.now() + Math.random(),
x: Math.random() * (width - 100) + 50,
y: height - 50,
vx: 0, vy: -1,
phase: 'bubble',
radius: 2,
life: 100
});
}
particles = nextParticles;
vaporPressure = vaporCount * 2;
// Draw particles
particles.forEach(p => {
ctx.beginPath();
if (p.phase === 'liquid_surface') {
ctx.fillStyle = '#38bdf8';
} else if (p.phase === 'solute_surface') {
ctx.fillStyle = SOLUTES[soluteType].color;
} else if (p.phase === 'vapor') {
ctx.fillStyle = 'rgba(226, 232, 240, 0.7)';
} else if (p.phase === 'bubble') {
ctx.strokeStyle = 'rgba(255, 255, 255, 0.8)';
ctx.lineWidth = 1.5;
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
ctx.stroke();
return;
}
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
ctx.fill();
});
updateStatus();
animationId = requestAnimationFrame(updateSimulation);
}
function updateStatus() {
const boilingPoint = calculateBoilingPoint();
const isBoiling = vaporPressure >= ATMOSPHERIC_PRESSURE;
const statusBox = document.getElementById('bp-status-box');
const statusText = document.getElementById('bp-status-text');
const vpDisplay = document.getElementById('bp-vp-display');
const tempDisplay = document.getElementById('bp-temp-display');
const bpDisplay = document.getElementById('bp-bp-display');
if (vpDisplay) vpDisplay.textContent = vaporPressure.toFixed(0);
if (tempDisplay) tempDisplay.textContent = temperature.toFixed(0);
if (bpDisplay) bpDisplay.textContent = boilingPoint.toFixed(1);
if (statusBox && statusText) {
if (isBoiling) {
statusBox.className = 'status-box active';
statusText.textContent = `غليان عند ${temperature.toFixed(0)}°C!`;
} else if (temperature >= boilingPoint) {
statusBox.className = 'status-box';
statusText.textContent = 'على وشك الغليان... زد التسخين قليلاً!';
} else if (heatingLevel > 0) {
statusBox.className = 'status-box';
statusText.textContent = 'جزيئات المذيب تتبخر من السطح.';
} else {
statusBox.className = 'status-box';
statusText.textContent = 'السائل في درجة حرارة الغرفة.';
}
}
// Update gauge
const maxGauge = ATMOSPHERIC_PRESSURE * 1.5;
const vpAngle = Math.min(180, (vaporPressure / maxGauge) * 180) - 90;
const apAngle = Math.min(180, (ATMOSPHERIC_PRESSURE / maxGauge) * 180) - 90;
const vpNeedle = document.getElementById('vp-needle');
const apMarker = document.getElementById('ap-marker');
const vpArc = document.getElementById('vp-arc');
if (vpNeedle) vpNeedle.setAttribute('transform', `rotate(${vpAngle} 50 50)`);
if (apMarker) apMarker.setAttribute('transform', `rotate(${apAngle} 50 50)`);
if (vpArc) {
const offset = 125.6 * (1 - Math.min(1, vaporPressure / maxGauge));
vpArc.setAttribute('stroke-dashoffset', offset);
}
}
function setupControls() {
const heatingSlider = document.getElementById('bp-heating-slider');
const soluteSlider = document.getElementById('bp-solute-slider');
const soluteBtns = document.querySelectorAll('.bp-solute-btn');
if (heatingSlider) {
heatingSlider.addEventListener('input', (e) => {
heatingLevel = parseInt(e.target.value);
});
}
if (soluteSlider) {
soluteSlider.addEventListener('input', (e) => {
soluteConcentration = parseInt(e.target.value);
initParticles();
});
}
soluteBtns.forEach(btn => {
btn.addEventListener('click', () => {
soluteType = btn.dataset.type;
soluteBtns.forEach(b => {
b.classList.remove('active');
b.style.background = 'transparent';
b.style.color = '#cbd5e1';
});
btn.classList.add('active');
btn.style.background = SOLUTES[soluteType].color;
btn.style.color = '#000';
initParticles();
});
});
document.getElementById('bp-reset-btn')?.addEventListener('click', () => {
heatingLevel = 0;
soluteConcentration = 0;
soluteType = 'sucrose';
if (heatingSlider) heatingSlider.value = 0;
if (soluteSlider) soluteSlider.value = 0;
soluteBtns.forEach(b => {
b.classList.remove('active');
b.style.background = 'transparent';
b.style.color = '#cbd5e1';
if (b.dataset.type === 'sucrose') {
b.classList.add('active');
b.style.background = SOLUTES.sucrose.color;
b.style.color = '#000';
}
});
initParticles();
});
}
container.innerHTML = `
<div class="simulation-container">
<div class="sim-header">
<h3 class="sim-title">محاكاة ارتفاع درجة الغليان</h3>
<button class="reset-btn" id="bp-reset-btn" title="إعادة تعيين">⟳</button>
</div>
<div class="canvas-container">
<canvas id="bp-canvas" width="${width}" height="${height}"></canvas>
<!-- Pressure Gauge -->
<div style="position: absolute; top: 16px; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.3); border-radius: 50%; padding: 8px;">
<svg width="80" height="80" viewBox="0 0 100 100">
<path d="M 10 50 A 40 40 0 0 1 90 50" stroke="#475569" stroke-width="8" fill="none" stroke-linecap="round"/>
<path id="vp-arc" d="M 10 50 A 40 40 0 0 1 90 50" stroke="url(#bpGrad)" stroke-width="8" fill="none" stroke-linecap="round"
stroke-dasharray="125.6" stroke-dashoffset="125.6" style="transition: all 0.3s;"/>
<g id="ap-marker" transform="rotate(0 50 50)">
<line x1="50" y1="10" x2="50" y2="2" stroke="white" stroke-width="2"/>
</g>
<g id="vp-needle" transform="rotate(-90 50 50)">
<path d="M 50 50 L 50 15" stroke="white" stroke-width="2" stroke-linecap="round"/>
</g>
<circle cx="50" cy="50" r="4" fill="white"/>
<defs>
<linearGradient id="bpGrad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#34d399"/>
<stop offset="100%" stop-color="#ef4444"/>
</linearGradient>
</defs>
</svg>
<div style="text-align: center; margin-top: 4px; font-size: 0.7rem; color: #94a3b8;">
<div>الضغط البخاري</div>
<div id="bp-vp-display" class="value-mono" style="color: #86efac; font-size: 1rem;">0</div>
</div>
</div>
<!-- Fire indicator -->
<div style="position: absolute; bottom: -10px; left: 50%; transform: translateX(-50%);">
<span id="fire-emoji" style="font-size: 2rem; opacity: ${heatingLevel/15}; transition: all 0.3s;">🔥</span>
</div>
</div>
<div id="bp-status-box" class="status-box">
<div id="bp-status-text" class="status-text">السائل في درجة حرارة الغرفة.</div>
</div>
<div class="controls-grid">
<div class="control-group">
<label class="control-label">مستوى التسخين</label>
<div class="slider-container">
<button onclick="document.getElementById('bp-heating-slider').value = Math.max(0, parseInt(document.getElementById('bp-heating-slider').value) - 1); heatingLevel = parseInt(document.getElementById('bp-heating-slider').value);"
style="background: #475569; color: white; border: none; width: 24px; height: 24px; border-radius: 4px; cursor: pointer;">-</button>
<input type="range" id="bp-heating-slider" min="0" max="10" value="0" class="accent-red" style="flex: 1;">
<button onclick="document.getElementById('bp-heating-slider').value = Math.min(10, parseInt(document.getElementById('bp-heating-slider').value) + 1); heatingLevel = parseInt(document.getElementById('bp-heating-slider').value);"
style="background: #475569; color: white; border: none; width: 24px; height: 24px; border-radius: 4px; cursor: pointer;">+</button>
</div>
<div class="value-display">
الحرارة: <span id="bp-temp-display" class="value-mono">20</span> °C
</div>
</div>
<div class="control-group">
<label class="control-label">كمية المذاب</label>
<input type="range" id="bp-solute-slider" min="0" max="10" value="0" class="accent-orange">
<div class="value-display">
درجة الغليان: <span id="bp-bp-display" class="value-mono">100.0</span> °C
</div>
</div>
<div class="control-group">
<label class="control-label">نوع المذاب</label>
<div class="btn-group">
<button class="btn-option bp-solute-btn active" data-type="sucrose" style="background: #f97316; color: #000;">
${SOLUTES.sucrose.name} (i=1)
</button>
<button class="btn-option bp-solute-btn" data-type="nacl">
${SOLUTES.nacl.name} (i=2)
</button>
</div>
</div>
</div>
<div class="info-text">
الغليان يحدث عندما يصل <span class="text-green">الضغط البخاري</span> إلى <span style="color: #fff; font-weight: bold;">الضغط الجوي</span>.
لاحظ كيف أن إضافة <span class="text-orange">المذاب</span> يعيق جزيئات المذيب من التبخر، مما يتطلب درجة حرارة أعلى للوصول إلى الغليان.
</div>
</div>
`;
setTimeout(() => {
canvas = document.getElementById('bp-canvas');
if (canvas) {
ctx = canvas.getContext('2d');
initParticles();
updateSimulation();
setupControls();
}
}, 100);
})();
/* ----------------------------------------------------------------
جدول ثوابت الانخفاض في درجة التجمد
---------------------------------------------------------------- */
(function() {
const container = document.getElementById('freezing-constants-table');
if (!container) return;
const tableData = [
{ solvent: 'الماء', freezingPoint: 0.0, kf: 1.86 },
{ solvent: 'الإيثانول', freezingPoint: -114.6, kf: 1.99 },
{ solvent: 'البنزين', freezingPoint: 5.5, kf: 5.12 },
{ solvent: 'حمض الخليك', freezingPoint: 16.6, kf: 3.90 },
{ solvent: 'رباعي كلوريد الكربون', freezingPoint: -22.9, kf: 29.8 },
];
container.innerHTML = `
<div class="simulation-container">
<h3 class="sim-title" style="text-align: center; margin-bottom: 16px;">
ثوابت الانخفاض المولالي لدرجة التجمد (K<sub>f</sub>) لبعض المذيبات الشائعة
</h3>
<div class="lesson-table-wrapper" style="margin: 0;">
<table class="lesson-table">
<thead>
<tr>
<th>المذيب</th>
<th>درجة التجمد (°C)</th>
<th>ثابت الانخفاض (K<sub>f</sub>) (°C·kg/mol)</th>
</tr>
</thead>
<tbody>
${tableData.map(row => `
<tr>
<td style="font-weight: bold; color: #fff;">${row.solvent}</td>
<td style="font-family: monospace;">${row.freezingPoint.toFixed(1)}</td>
<td style="font-family: monospace;">${row.kf.toFixed(2)}</td>
</tr>
`).join('')}
</tbody>
</table>
</div>
<p style="margin-top: 12px; font-size: 0.8rem; color: #94a3b8; text-align: center;">
ملاحظة: ثابت الانخفاض (K<sub>f</sub>) هو خاصية مميزة لكل مذيب.
</p>
</div>
`;
})();
/* ----------------------------------------------------------------
محاكاة الانخفاض في درجة التجمد
---------------------------------------------------------------- */
(function() {
const container = document.getElementById('freezing-point-sim');
if (!container) return;
const SOLUTES = {
sucrose: { name: 'السكر (لا إلكتروليتي)', formula: 'C₁₂H₂₂O₁₁', i: 1, color: '#f97316' },
nacl: { name: 'ملح الطعام (إلكتروليت)', formula: 'NaCl', i: 2, color: '#fde047' },
cacl2: { name: 'كلوريد الكالسيوم (إلكتروليت)', formula: 'CaCl₂', i: 3, color: '#ec4899' }
};
let temperature = 10;
let soluteConcentration = 2;
let soluteType = 'sucrose';
let particles = [];
let animationId = null;
let canvas, ctx;
const width = 450;
const height = 350;
const beakerWidth = 200;
const liquidLevel = height - 150;
const numSolventParticles = 50;
const maxSoluteParticles = 15;
function initParticles() {
particles = [];
let idCounter = 0;
const createGridTargets = (offsetX) => {
const targets = [];
const rows = 5, cols = 10, spacing = 20;
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
targets.push({
x: offsetX + 25 + j * spacing + (i % 2) * spacing / 2,
y: liquidLevel + 20 + i * spacing
});
}
}
return targets;
};
const solutionOffsetX = 0;
const pureOffsetX = width - beakerWidth;
const pureTargets = createGridTargets(pureOffsetX);
const solutionTargets = createGridTargets(solutionOffsetX);
const numSolute = Math.floor((soluteConcentration / 10) * maxSoluteParticles);
// Solution particles (left beaker)
for (let i = 0; i < numSolventParticles; i++) {
particles.push({
id: idCounter++,
beaker: 'solution',
x: solutionOffsetX + 20 + Math.random() * (beakerWidth - 40),
y: liquidLevel + Math.random() * (height - liquidLevel - 40),
vx: (Math.random() - 0.5),
vy: (Math.random() - 0.5),
type: 'solvent',
radius: 3.5,
targetX: solutionTargets[i].x,
targetY: solutionTargets[i].y
});
}
for (let i = 0; i < numSolute; i++) {
particles.push({
id: idCounter++,
beaker: 'solution',
x: solutionOffsetX + 20 + Math.random() * (beakerWidth - 40),
y: liquidLevel + Math.random() * (height - liquidLevel - 40),
vx: (Math.random() - 0.5) * 0.2,
vy: (Math.random() - 0.5) * 0.2,
type: 'solute',
radius: 5
});
}
// Pure water particles (right beaker)
for (let i = 0; i < numSolventParticles; i++) {
particles.push({
id: idCounter++,
beaker: 'pure',
x: pureOffsetX + 20 + Math.random() * (beakerWidth - 40),
y: liquidLevel + Math.random() * (height - liquidLevel - 40),
vx: (Math.random() - 0.5),
vy: (Math.random() - 0.5),
type: 'solvent',
radius: 3.5,
targetX: pureTargets[i].x,
targetY: pureTargets[i].y
});
}
}
function drawIceCrystal(x, y, size, opacity) {
if (!ctx) return;
ctx.save();
ctx.translate(x, y);
ctx.strokeStyle = `rgba(200, 220, 255, ${opacity * 0.6})`;
ctx.lineWidth = size / 5;
for (let i = 0; i < 6; i++) {
ctx.rotate(Math.PI / 3);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, size);
ctx.stroke();
}
ctx.restore();
}
function calculateFreezingPoints() {
const Kf = 1.86;
const molality = (soluteConcentration / 10) * 2;
const depression = SOLUTES[soluteType].i * Kf * molality;
return {
pure: 0,
solution: -depression,
depression: depression
};
}
function updateSimulation() {
if (!ctx) return;
const fps = calculateFreezingPoints();
const isPureFreezing = temperature <= fps.pure;
const isSolutionFreezing = temperature <= fps.solution;
const pureFreezeFactor = isPureFreezing ? Math.min(1, (fps.pure - temperature) / 5) : 0;
const solutionFreezeFactor = isSolutionFreezing ? Math.min(1, (fps.solution - temperature) / 5) : 0;
ctx.clearRect(0, 0, width, height);
// Draw beakers
const drawBeaker = (offsetX, freezeFactor) => {
ctx.strokeStyle = '#9ca3af';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(offsetX + 10, 50);
ctx.lineTo(offsetX + 10, height - 40);
ctx.quadraticCurveTo(offsetX + beakerWidth / 2, height - 20, offsetX + beakerWidth - 10, height - 40);
ctx.lineTo(offsetX + beakerWidth - 10, 50);
ctx.stroke();
// liquid
ctx.fillStyle = `rgba(56, 189, 248, ${0.2 * (1 - freezeFactor)})`;
ctx.fillRect(offsetX + 12, liquidLevel, beakerWidth - 24, height - liquidLevel - 30);
// ice
ctx.fillStyle = `rgba(200, 220, 255, ${0.3 * freezeFactor})`;
ctx.fillRect(offsetX + 12, liquidLevel, beakerWidth - 24, height - liquidLevel - 30);
if (freezeFactor > 0.1) {
for (let i = 0; i < freezeFactor * 10; i++) {
drawIceCrystal(
offsetX + Math.random() * beakerWidth,
liquidLevel + Math.random() * (height - liquidLevel - 40),
10 + Math.random() * 15,
freezeFactor
);
}
}
};
drawBeaker(0, solutionFreezeFactor);
drawBeaker(width - beakerWidth, pureFreezeFactor);
// Update and draw particles
particles.forEach(p => {
const beakerOffset = p.beaker === 'solution' ? 0 : width - beakerWidth;
const freezeFactor = p.beaker === 'solution' ? solutionFreezeFactor : pureFreezeFactor;
const speedMultiplier = Math.max(0.1, 1 - freezeFactor);
if (freezeFactor > 0 && p.type === 'solvent') {
p.vx += (p.targetX - p.x) * 0.05 * freezeFactor;
p.vy += (p.targetY - p.y) * 0.05 * freezeFactor;
p.vx += (Math.random() - 0.5) * 0.2;
p.vy += (Math.random() - 0.5) * 0.2;
} else {
p.vx += (Math.random() - 0.5) * 0.2;
p.vy += (Math.random() - 0.5) * 0.2;
}
p.x += p.vx * speedMultiplier;
p.y += p.vy * speedMultiplier;
// Wall collisions
const leftWall = beakerOffset + 15;
const rightWall = beakerOffset + beakerWidth - 15;
if (p.x < leftWall || p.x > rightWall) {
p.vx *= -1;
p.x = Math.max(leftWall, Math.min(p.x, rightWall));
}
if (p.y > height - 45 || p.y < liquidLevel) {
p.vy *= -1;
p.y = Math.max(liquidLevel, Math.min(p.y, height - 45));
}
p.vx *= 0.9;
p.vy *= 0.9;
ctx.beginPath();
if (p.type === 'solute') ctx.fillStyle = SOLUTES[soluteType].color;
else ctx.fillStyle = '#38bdf8';
ctx.globalAlpha = 1 - freezeFactor * 0.5;
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
ctx.fill();
ctx.globalAlpha = 1;
});
// Update displays
const tempDisplay = document.getElementById('fp-temp-display');
const pureFpDisplay = document.getElementById('fp-pure-display');
const solFpDisplay = document.getElementById('fp-sol-display');
const depressionDisplay = document.getElementById('fp-depression-display');
if (tempDisplay) tempDisplay.textContent = temperature.toFixed(1);
if (pureFpDisplay) pureFpDisplay.textContent = fps.pure.toFixed(1);
if (solFpDisplay) solFpDisplay.textContent = fps.solution.toFixed(1);
if (depressionDisplay) depressionDisplay.textContent = fps.depression.toFixed(2);
// Update status indicators
const pureStatus = document.getElementById('fp-pure-status');
const solStatus = document.getElementById('fp-sol-status');
if (pureStatus) {
if (isPureFreezing) {
pureStatus.innerHTML = '<span style="color: #60a5fa; animation: pulse 2s infinite;">❄️ في حالة تجمد</span>';
} else {
pureStatus.innerHTML = '<span style="color: #94a3b8;">سائل</span>';
}
}
if (solStatus) {
if (isSolutionFreezing) {
solStatus.innerHTML = '<span style="color: #60a5fa; animation: pulse 2s infinite;">❄️ في حالة تجمد</span>';
} else {
solStatus.innerHTML = '<span style="color: #94a3b8;">سائل</span>';
}
}
animationId = requestAnimationFrame(updateSimulation);
}
container.innerHTML = `
<div class="simulation-container">
<div class="sim-header">
<h3 class="sim-title">محاكاة الانخفاض في درجة التجمد</h3>
<button class="reset-btn" id="fp-reset-btn" title="إعادة تعيين">⟳</button>
</div>
<div class="canvas-container">
<canvas id="fp-canvas" width="${width}" height="${height}"></canvas>
<div class="beaker-labels">
<div class="beaker-info">
<h4 style="color: #fff; margin-bottom: 8px;">المحلول</h4>
<div style="font-size: 0.8rem; color: #94a3b8;">
<div>درجة الحرارة: <span id="fp-temp-display" class="value-mono">10.0</span> °C</div>
<div>درجة التجمد: <span id="fp-sol-display" class="value-mono">0.0</span> °C</div>
</div>
<div id="fp-sol-status" style="margin-top: 8px; font-size: 0.9rem;"></div>
</div>
<div class="beaker-info">
<h4 style="color: #fff; margin-bottom: 8px;">الماء النقي</h4>
<div style="font-size: 0.8rem; color: #94a3b8;">
<div>درجة الحرارة: <span class="value-mono">${temperature.toFixed(1)}</span> °C</div>
<div>درجة التجمد: <span id="fp-pure-display" class="value-mono">0.0</span> °C</div>
</div>
<div id="fp-pure-status" style="margin-top: 8px; font-size: 0.9rem;"></div>
</div>
</div>
</div>
<div class="controls-grid">
<div class="control-group">
<label class="control-label">درجة الحرارة (<span id="fp-temp-label">10</span>°C)</label>
<input type="range" id="fp-temp-slider" min="-20" max="20" step="0.5" value="${temperature}" class="accent-blue">
</div>
<div class="control-group">
<label class="control-label">تركيز المذاب</label>
<input type="range" id="fp-solute-slider" min="0" max="10" step="1" value="${soluteConcentration}" class="accent-orange">
</div>
<div class="control-group">
<label class="control-label">نوع المذاب (معامل فانت هوف)</label>
<div class="btn-group" style="flex-direction: column;">
${Object.keys(SOLUTES).map(key => `
<button class="btn-option fp-solute-btn ${key === soluteType ? 'active' : ''}"
data-type="${key}"
style="${key === soluteType ? `background: ${SOLUTES[key].color}; color: #000;` : ''}">
${SOLUTES[key].formula} (i=${SOLUTES[key].i})
</button>
`).join('')}
</div>
</div>
</div>
<div class="status-box" style="margin-top: 16px;">
<p style="font-size: 1.1rem; font-weight: bold; color: #fff;">
الانخفاض في درجة تجمد المحلول:
<span id="fp-depression-display" class="value-mono" style="color: #7dd3fc;">0.00</span> °C
</p>
</div>
<div class="info-text">
جسيمات المذاب تعيق تكوين الشبكة البلورية للماء، مما يتطلب درجات حرارة أقل لحدوث التجمد.
كلما زاد عدد الجسيمات (بزيادة التركيز أو استخدام مذاب يتفكك لأيونات أكثر)، زاد الانخفاض في درجة التجمد.
</div>
</div>
`;
setTimeout(() => {
canvas = document.getElementById('fp-canvas');
if (canvas) {
ctx = canvas.getContext('2d');
initParticles();
updateSimulation();
// Setup controls
const tempSlider = document.getElementById('fp-temp-slider');
const soluteSlider = document.getElementById('fp-solute-slider');
const soluteBtns = document.querySelectorAll('.fp-solute-btn');
const tempLabel = document.getElementById('fp-temp-label');
if (tempSlider) {
tempSlider.addEventListener('input', (e) => {
temperature = parseFloat(e.target.value);
if (tempLabel) tempLabel.textContent = temperature.toFixed(1);
});
}
if (soluteSlider) {
soluteSlider.addEventListener('input', (e) => {
soluteConcentration = parseInt(e.target.value);
initParticles();
});
}
soluteBtns.forEach(btn => {
btn.addEventListener('click', () => {
soluteType = btn.dataset.type;
soluteBtns.forEach(b => {
b.classList.remove('active');
b.style.background = 'transparent';
b.style.color = '#cbd5e1';
});
btn.classList.add('active');
btn.style.background = SOLUTES[soluteType].color;
btn.style.color = '#000';
initParticles();
});
});
document.getElementById('fp-reset-btn')?.addEventListener('click', () => {
temperature = 10;
soluteConcentration = 2;
soluteType = 'sucrose';
if (tempSlider) {
tempSlider.value = 10;
if (tempLabel) tempLabel.textContent = '10.0';
}
if (soluteSlider) soluteSlider.value = 2;
soluteBtns.forEach(b => {
b.classList.remove('active');
b.style.background = 'transparent';
b.style.color = '#cbd5e1';
if (b.dataset.type === 'sucrose') {
b.classList.add('active');
b.style.background = SOLUTES.sucrose.color;
b.style.color = '#000';
}
});
initParticles();
});
}
}, 100);
})();
/* ----------------------------------------------------------------
محاكاة الضغط الأسموزي
---------------------------------------------------------------- */
(function() {
const container = document.getElementById('osmosis-sim');
if (!container) return;
let soluteConcentration = 4;
let appliedPressure = 0;
let particles = [];
let animationId = null;
let canvas, ctx;
let currentHeightDiff = 0;
const width = 300;
const height = 220;
const armWidth = 100;
const bottomThickness = 30;
const membraneWidth = 8;
const membraneX = width / 2;
const leftArmX = (width / 2) - armWidth - membraneWidth / 2;
const rightArmX = (width / 2) + membraneWidth / 2;
function initParticles() {
particles = [];
let idCounter = 0;
// Solvent on left side (pure)
for (let i = 0; i < 40; i++) {
particles.push({
id: idCounter++,
type: 'solvent',
x: leftArmX + Math.random() * armWidth,
y: height / 2 + Math.random() * (height / 2 - bottomThickness),
vx: (Math.random() - 0.5) * 0.5,
vy: (Math.random() - 0.5) * 0.5,
radius: 3.5,
color: '#60a5fa'
});
}
// Solvent on right side (solution)
for (let i = 0; i < 40; i++) {
particles.push({
id: idCounter++,
type: 'solvent',
x: rightArmX + Math.random() * armWidth,
y: height / 2 + Math.random() * (height / 2 - bottomThickness),
vx: (Math.random() - 0.5) * 0.5,
vy: (Math.random() - 0.5) * 0.5,
radius: 3.5,
color: '#60a5fa'
});
}
updateSoluteParticles();
}
function updateSoluteParticles() {
// Remove old solute particles
particles = particles.filter(p => p.type !== 'solute');
const numSolute = soluteConcentration * 3;
for (let i = 0; i < numSolute; i++) {
particles.push({
id: 1000 + i,
type: 'solute',
x: rightArmX + Math.random() * armWidth,
y: height / 2 + Math.random() * (height / 2 - bottomThickness),
vx: (Math.random() - 0.5) * 0.2,
vy: (Math.random() - 0.5) * 0.2,
radius: 5,
color: '#f97316'
});
}
}
function updateSimulation() {
if (!ctx) return;
const osmoticPressure = soluteConcentration * 2;
const netPressure = osmoticPressure - appliedPressure;
const targetHeightDiff = Math.max(-60, Math.min(60, netPressure * 3));
currentHeightDiff += (targetHeightDiff - currentHeightDiff) * 0.05;
const leftLevel = height / 2 + currentHeightDiff / 2;
const rightLevel = height / 2 - currentHeightDiff / 2;
ctx.clearRect(0, 0, width, height);
// Draw container walls
ctx.strokeStyle = '#9ca3af';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(leftArmX, 0);
ctx.lineTo(leftArmX, height - bottomThickness);
ctx.arcTo(leftArmX, height, leftArmX + bottomThickness, height, bottomThickness);
ctx.lineTo(rightArmX + armWidth - bottomThickness, height);
ctx.arcTo(rightArmX + armWidth, height, rightArmX + armWidth, height - bottomThickness, bottomThickness);
ctx.lineTo(rightArmX + armWidth, 0);
ctx.moveTo(leftArmX + armWidth, 0);
ctx.lineTo(leftArmX + armWidth, height);
ctx.stroke();
// Draw liquids
const drawLiquid = (levelY, startX, armW) => {
ctx.beginPath();
ctx.moveTo(startX, levelY);
ctx.lineTo(startX, height - bottomThickness);
ctx.arcTo(startX, height, startX + bottomThickness, height, bottomThickness);
ctx.lineTo(startX + armW - bottomThickness, height);
ctx.arcTo(startX + armW, height, startX + armW, height - bottomThickness, bottomThickness);
ctx.lineTo(startX + armW, levelY);
ctx.closePath();
};
ctx.fillStyle = "rgba(56, 189, 248, 0.4)";
drawLiquid(leftLevel, leftArmX, armWidth);
ctx.fill();
drawLiquid(rightLevel, rightArmX, armWidth);
ctx.fill();
// Draw membrane
ctx.fillStyle = '#475569';
ctx.fillRect(membraneX - membraneWidth / 2, 0, membraneWidth, height);
// Update and draw particles
particles.forEach(p => {
p.x += p.vx;
p.y += p.vy;
const armStartX = p.x < membraneX ? leftArmX : rightArmX;
const liquidLevel = p.x < membraneX ? leftLevel : rightLevel;
if (p.x < armStartX + p.radius || p.x > armStartX + armWidth - p.radius) p.vx *= -1;
if (p.y > height - p.radius) { p.y = height - p.radius; p.vy *= -1; }
if (p.y < liquidLevel + p.radius) { p.y = liquidLevel + p.radius; p.vy *= -1; }
if (p.x + p.radius > membraneX - membraneWidth / 2 && p.x - p.radius < membraneX + membraneWidth / 2) {
if (p.type === 'solute') {
p.vx *= -1;
p.x = p.x < membraneX ? membraneX - membraneWidth / 2 - p.radius : membraneX + membraneWidth / 2 + p.radius;
}
}
ctx.beginPath();
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
ctx.fillStyle = p.color;
ctx.fill();
});
// Draw applied pressure indicator
if (appliedPressure > 0) {
const pressureIndicatorY = rightLevel - 10;
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
ctx.fillRect(rightArmX, pressureIndicatorY, armWidth, 5);
ctx.font = '12px Cairo';
ctx.textAlign = 'center';
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
ctx.fillText('ضغط مطبق', rightArmX + armWidth / 2, pressureIndicatorY - 5);
// Draw arrows
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.lineWidth = 1;
for (let i = 0; i < 5; i++) {
ctx.beginPath();
ctx.moveTo(rightArmX + armWidth / 2 - 15 + i * 7.5, pressureIndicatorY - 2);
ctx.lineTo(rightArmX + armWidth / 2, pressureIndicatorY - 10);
ctx.lineTo(rightArmX + armWidth / 2 + 15 - i * 7.5, pressureIndicatorY - 2);
ctx.stroke();
}
}
animationId = requestAnimationFrame(updateSimulation);
}
container.innerHTML = `
<div class="simulation-container">
<div class="sim-header">
<h3 class="sim-title">محاكاة الضغط الأسموزي</h3>
<button class="reset-btn" id="os-reset-btn" title="إعادة تعيين">⟳</button>
</div>
<div style="display: flex; flex-direction: column; align-items: center;">
<div class="canvas-container" style="background: rgba(15, 23, 42, 0.5);">
<canvas id="os-canvas" width="${width}" height="${height}"></canvas>
</div>
<div class="legend" style="margin-top: 8px;">
<div class="legend-item">
<div class="legend-dot" style="background: #60a5fa;"></div>
<span>مذيب (ماء)</span>
</div>
<div class="legend-item">
<div class="legend-dot" style="background: #f97316;"></div>
<span>مذاب</span>
</div>
</div>
</div>
<div class="controls-grid" style="max-width: 500px; margin: 16px auto 0;">
<div class="control-group">
<label class="control-label">تركيز المذاب (يزيد الضغط الأسموزي)</label>
<input type="range" id="os-conc-slider" min="0" max="10" step="1" value="${soluteConcentration}" class="accent-orange">
</div>
<div class="control-group">
<label class="control-label">الضغط المطبق (على المحلول)</label>
<input type="range" id="os-pressure-slider" min="0" max="20" step="1" value="${appliedPressure}" class="accent-teal">
</div>
</div>
<div class="info-text">
لاحظ كيف ينتقل المذيب (الماء) من الجانب الأقل تركيزًا إلى الأعلى تركيزًا ليعادل الفرق.
الضغط المطبق يعاكس هذه العملية، وإذا كان كافيًا، يمكنه عكسها (الأسموزية العكسية).
</div>
</div>
`;
setTimeout(() => {
canvas = document.getElementById('os-canvas');
if (canvas) {
ctx = canvas.getContext('2d');
initParticles();
updateSimulation();
const concSlider = document.getElementById('os-conc-slider');
const pressureSlider = document.getElementById('os-pressure-slider');
if (concSlider) {
concSlider.addEventListener('input', (e) => {
soluteConcentration = parseInt(e.target.value);
updateSoluteParticles();
});
}
if (pressureSlider) {
pressureSlider.addEventListener('input', (e) => {
appliedPressure = parseInt(e.target.value);
});
}
document.getElementById('os-reset-btn')?.addEventListener('click', () => {
soluteConcentration = 4;
appliedPressure = 0;
if (concSlider) concSlider.value = 4;
if (pressureSlider) pressureSlider.value = 0;
updateSoluteParticles();
});
}
}, 100);
})();
</script>
</body>
</html>