Meta Description" name="description" />
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Les Vecteurs — 3ème | Capsule Interactive</title>
<!-- MathJax -->
<script>
MathJax = {
tex: { inlineMath: [['$','$'], ['\\(','\\)']], displayMath: [['$$','$$'], ['\\[','\\]']] },
options: { skipHtmlTags: ['script','noscript','style','textarea','pre'] }
};
</script>
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" async></script>
<style>
/* ===== DESIGN SYSTEM ===== */
@import url('https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:wght@300;400;500&display=swap');
:root {
--bg: #0d0f1a;
--surface: #141726;
--card: #1a1f35;
--border: #272d4a;
--accent1: #5b8fff; /* bleu vif */
--accent2: #ff6b6b; /* rouge coral */
--accent3: #4ecdc4; /* turquoise */
--accent4: #ffd166; /* jaune */
--accent5: #a29bfe; /* violet doux */
--text: #e8ecf8;
--muted: #8892b0;
--success: #56cf8c;
--radius: 16px;
--shadow: 0 8px 32px rgba(0,0,0,.4);
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
font-family: 'DM Sans', sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.65;
overflow-x: hidden;
}
/* ===== HEADER ===== */
header {
position: relative;
padding: 80px 24px 60px;
text-align: center;
overflow: hidden;
}
header::before {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(ellipse 80% 60% at 50% -10%, rgba(91,143,255,.25) 0%, transparent 70%);
pointer-events: none;
}
.header-badge {
display: inline-block;
background: rgba(91,143,255,.15);
border: 1px solid rgba(91,143,255,.4);
color: var(--accent1);
font-size: .8rem;
font-weight: 600;
letter-spacing: .12em;
text-transform: uppercase;
padding: 6px 18px;
border-radius: 999px;
margin-bottom: 20px;
animation: fadeUp .6s ease both;
}
header h1 {
font-family: 'Syne', sans-serif;
font-size: clamp(2.6rem, 6vw, 5rem);
font-weight: 800;
line-height: 1.05;
animation: fadeUp .6s .1s ease both;
}
header h1 span { color: var(--accent1); }
header p.subtitle {
max-width: 560px;
margin: 16px auto 0;
color: var(--muted);
font-size: 1.05rem;
animation: fadeUp .6s .2s ease both;
}
/* nav pills */
.nav-pills {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
margin-top: 36px;
animation: fadeUp .6s .3s ease both;
}
.nav-pill {
background: var(--card);
border: 1px solid var(--border);
color: var(--muted);
font-size: .85rem;
font-weight: 500;
padding: 8px 18px;
border-radius: 999px;
cursor: pointer;
transition: all .2s;
text-decoration: none;
}
.nav-pill:hover { border-color: var(--accent1); color: var(--accent1); }
/* ===== LAYOUT ===== */
main { max-width: 1100px; margin: 0 auto; padding: 0 20px 100px; }
/* ===== SECTION ===== */
.section {
margin-bottom: 60px;
opacity: 0;
transform: translateY(30px);
transition: opacity .6s ease, transform .6s ease;
}
.section.visible { opacity: 1; transform: none; }
.section-header {
display: flex;
align-items: center;
gap: 14px;
margin-bottom: 24px;
}
.section-number {
width: 42px; height: 42px;
background: linear-gradient(135deg, var(--accent1), var(--accent5));
border-radius: 12px;
display: flex; align-items: center; justify-content: center;
font-family: 'Syne', sans-serif;
font-weight: 800;
font-size: .95rem;
flex-shrink: 0;
}
.section-title {
font-family: 'Syne', sans-serif;
font-size: 1.55rem;
font-weight: 700;
}
/* ===== CARDS ===== */
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 28px;
box-shadow: var(--shadow);
}
.card + .card { margin-top: 16px; }
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
}
.highlight-card {
border-color: rgba(91,143,255,.5);
background: linear-gradient(135deg, rgba(91,143,255,.08), rgba(162,155,254,.06));
}
/* ===== DEFINITION CHIPS ===== */
.def-chips { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 16px; }
.def-chip {
display: flex; align-items: flex-start; gap: 10px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 14px 18px;
flex: 1; min-width: 200px;
}
.def-chip .chip-icon {
font-size: 1.4rem; margin-top: 2px; flex-shrink: 0;
}
.def-chip .chip-label { font-size: .75rem; text-transform: uppercase; letter-spacing: .1em; color: var(--muted); }
.def-chip .chip-value { font-size: .95rem; margin-top: 2px; }
/* ===== FORMULA BOX ===== */
.formula-box {
background: linear-gradient(135deg, rgba(78,205,196,.08), rgba(91,143,255,.06));
border: 1px solid rgba(78,205,196,.35);
border-radius: 12px;
padding: 20px 24px;
margin: 16px 0;
text-align: center;
font-size: 1.1rem;
}
/* ===== CANVAS WIDGETS ===== */
.widget {
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
box-shadow: var(--shadow);
}
.widget-header {
padding: 16px 22px;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 10px;
}
.widget-title {
font-family: 'Syne', sans-serif;
font-weight: 700;
font-size: 1rem;
display: flex; align-items: center; gap: 8px;
}
.widget-tag {
font-size: .72rem;
font-weight: 600;
letter-spacing: .1em;
text-transform: uppercase;
padding: 3px 10px;
border-radius: 999px;
background: rgba(91,143,255,.15);
color: var(--accent1);
}
.widget-body { padding: 20px; }
canvas {
display: block;
border-radius: 10px;
background: #0f1220;
cursor: crosshair;
touch-action: none;
max-width: 100%;
}
.info-panel {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 10px;
padding: 14px 18px;
margin-top: 14px;
font-size: .9rem;
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.info-item { display: flex; flex-direction: column; gap: 2px; }
.info-label { font-size: .73rem; text-transform: uppercase; letter-spacing: .1em; color: var(--muted); }
.info-value { font-family: 'Syne', sans-serif; font-weight: 700; font-size: 1.05rem; }
.info-value.blue { color: var(--accent1); }
.info-value.red { color: var(--accent2); }
.info-value.teal { color: var(--accent3); }
.info-value.gold { color: var(--accent4); }
/* ===== BUTTONS ===== */
.btn {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 10px 20px;
border-radius: 10px;
font-family: 'DM Sans', sans-serif;
font-size: .88rem;
font-weight: 500;
cursor: pointer;
border: 1px solid transparent;
transition: all .2s;
}
.btn-primary {
background: var(--accent1);
color: #fff;
}
.btn-primary:hover { background: #7aa5ff; transform: translateY(-1px); }
.btn-ghost {
background: transparent;
border-color: var(--border);
color: var(--muted);
}
.btn-ghost:hover { border-color: var(--accent1); color: var(--accent1); }
.btn-danger {
background: rgba(255,107,107,.15);
border-color: rgba(255,107,107,.4);
color: var(--accent2);
}
.btn-danger:hover { background: rgba(255,107,107,.25); }
.btn-success {
background: rgba(86,207,140,.15);
border-color: rgba(86,207,140,.4);
color: var(--success);
}
.btn-success:hover { background: rgba(86,207,140,.25); }
.btn-group { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
/* ===== EXERCISES ===== */
.exercise {
background: var(--surface);
border: 1px solid var(--border);
border-left: 4px solid var(--accent4);
border-radius: 12px;
padding: 22px 24px;
margin-bottom: 16px;
}
.exercise-num {
font-size: .72rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .1em;
color: var(--accent4);
margin-bottom: 8px;
}
.exercise h4 { font-family: 'Syne', sans-serif; font-size: 1rem; margin-bottom: 10px; }
.exercise p { color: var(--muted); font-size: .93rem; }
.answer-input {
background: var(--card);
border: 1px solid var(--border);
color: var(--text);
font-family: 'DM Sans', sans-serif;
font-size: .95rem;
padding: 10px 14px;
border-radius: 8px;
width: 100%;
margin-top: 10px;
outline: none;
transition: border-color .2s;
}
.answer-input:focus { border-color: var(--accent1); }
.feedback {
margin-top: 10px;
padding: 10px 14px;
border-radius: 8px;
font-size: .9rem;
display: none;
}
.feedback.correct {
background: rgba(86,207,140,.12);
border: 1px solid rgba(86,207,140,.35);
color: var(--success);
display: block;
}
.feedback.wrong {
background: rgba(255,107,107,.12);
border: 1px solid rgba(255,107,107,.35);
color: var(--accent2);
display: block;
}
/* ===== PROF MODE ===== */
.prof-mode {
border: 2px solid var(--accent4);
border-radius: var(--radius);
overflow: hidden;
}
.prof-header {
background: linear-gradient(135deg, rgba(255,209,102,.12), rgba(255,209,102,.05));
border-bottom: 1px solid rgba(255,209,102,.3);
padding: 16px 22px;
display: flex;
align-items: center;
gap: 10px;
}
.prof-badge {
background: var(--accent4);
color: #0d0f1a;
font-size: .72rem;
font-weight: 800;
letter-spacing: .12em;
text-transform: uppercase;
padding: 4px 12px;
border-radius: 999px;
}
.prof-tools {
padding: 14px 20px;
border-bottom: 1px solid var(--border);
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
}
.tool-btn {
padding: 8px 14px;
border-radius: 8px;
font-size: .83rem;
font-weight: 500;
cursor: pointer;
border: 1px solid var(--border);
background: var(--surface);
color: var(--muted);
transition: all .2s;
display: flex; align-items: center; gap: 6px;
}
.tool-btn:hover { border-color: var(--accent1); color: var(--accent1); }
.tool-btn.active { background: rgba(91,143,255,.15); border-color: var(--accent1); color: var(--accent1); }
/* color picker row */
.color-row { display: flex; gap: 8px; align-items: center; }
.color-dot {
width: 22px; height: 22px;
border-radius: 50%;
cursor: pointer;
border: 2px solid transparent;
transition: border-color .15s, transform .15s;
}
.color-dot:hover { transform: scale(1.15); }
.color-dot.active { border-color: #fff; }
input[type="range"] {
accent-color: var(--accent1);
width: 90px;
}
/* ===== GEOGEBRA ===== */
.ggb-wrap {
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--border);
position: relative;
background: #fff;
}
.ggb-wrap iframe { display: block; width: 100%; }
/* ===== PROGRESS BAR ===== */
.progress-wrap {
position: fixed;
top: 0; left: 0; right: 0;
height: 3px;
background: transparent;
z-index: 999;
}
#progress-bar {
height: 100%;
background: linear-gradient(90deg, var(--accent1), var(--accent3));
width: 0%;
transition: width .1s;
}
/* ===== ANIMATIONS ===== */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: none; }
}
@keyframes pulse {
0%,100% { box-shadow: 0 0 0 0 rgba(91,143,255,.4); }
50% { box-shadow: 0 0 0 8px rgba(91,143,255,0); }
}
/* ===== TOOLTIP ===== */
.tooltip-text {
background: rgba(20,23,38,.95);
border: 1px solid var(--border);
border-radius: 8px;
padding: 6px 10px;
font-size: .8rem;
color: var(--text);
pointer-events: none;
position: absolute;
z-index: 99;
white-space: nowrap;
}
/* ===== SCROLLBAR ===== */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
/* ===== RESPONSIVE ===== */
@media (max-width: 640px) {
header { padding: 60px 16px 40px; }
.widget-header { flex-direction: column; align-items: flex-start; }
canvas { height: 260px !important; }
.info-panel { flex-direction: column; gap: 10px; }
}
</style>
</head>
<body>
<!-- Progress bar -->
<div class="progress-wrap"><div id="progress-bar"></div></div>
<!-- ===== HEADER ===== -->
<header>
<div class="header-badge">Mathématiques · 3ème</div>
<h1>Les <span>Vecteurs</span></h1>
<p class="subtitle">Capsule interactive — comprends, explore et maîtrise les vecteurs avec des outils dynamiques</p>
<nav class="nav-pills">
<a class="nav-pill" href="#intro">Introduction</a>
<a class="nav-pill" href="#definition">Définition</a>
<a class="nav-pill" href="#egaux">Vecteurs égaux</a>
<a class="nav-pill" href="#chasles">Relation de Chasles</a>
<a class="nav-pill" href="#coordonnees">Coordonnées</a>
<a class="nav-pill" href="#norme">Norme</a>
<a class="nav-pill" href="#geogebra">GeoGebra</a>
<a class="nav-pill" href="#exercices">Exercices</a>
<a class="nav-pill" href="#prof">Mode Prof</a>
</nav>
</header>
<main>
<!-- ===== 1. INTRODUCTION ===== -->
<section class="section" id="intro">
<div class="section-header">
<div class="section-number">1</div>
<div class="section-title">Introduction intuitive</div>
</div>
<div class="card card-grid" style="display:grid">
<div style="grid-template-columns:1fr 1fr;display:grid;gap:16px">
<div class="card highlight-card">
<p style="font-size:2rem;margin-bottom:10px">🚶</p>
<h3 style="font-family:'Syne',sans-serif;margin-bottom:8px">Un déplacement</h3>
<p style="color:var(--muted)">Imagine que tu te déplaces de la maison jusqu'à l'école. Ce déplacement a une <strong style="color:var(--text)">direction</strong> (la rue), un <strong style="color:var(--text)">sens</strong> (maison → école) et une <strong style="color:var(--text)">longueur</strong>.</p>
</div>
<div class="card highlight-card">
<p style="font-size:2rem;margin-bottom:10px">➡️</p>
<h3 style="font-family:'Syne',sans-serif;margin-bottom:8px">Un vecteur, c'est ça !</h3>
<p style="color:var(--muted)">Un <strong style="color:var(--accent1)">vecteur</strong> représente mathématiquement ce déplacement. On le dessine avec une flèche. Peu importe où tu commences, si tu fais le même déplacement, c'est le <strong style="color:var(--text)">même vecteur</strong>.</p>
</div>
</div>
</div>
<div class="card" style="margin-top:16px;padding:0;overflow:hidden">
<div class="widget-header">
<span class="widget-title">🎯 Déplace les points A et B</span>
<span class="widget-tag">Interactif</span>
</div>
<div class="widget-body">
<canvas id="introCanvas" width="660" height="300" style="width:100%;height:300px"></canvas>
<div class="info-panel" id="introInfo">
<div class="info-item"><span class="info-label">Vecteur</span><span class="info-value blue" id="introVec">AB</span></div>
<div class="info-item"><span class="info-label">Coordonnées</span><span class="info-value teal" id="introCoord">(0, 0)</span></div>
<div class="info-item"><span class="info-label">Norme</span><span class="info-value gold" id="introNorm">0</span></div>
<div class="info-item"><span class="info-label">Direction</span><span class="info-value" id="introAngle" style="color:var(--accent5)">0°</span></div>
</div>
</div>
</div>
</section>
<!-- ===== 2. DEFINITION ===== -->
<section class="section" id="definition">
<div class="section-header">
<div class="section-number">2</div>
<div class="section-title">Définition d'un vecteur</div>
</div>
<div class="card">
<p>Un <strong style="color:var(--accent1)">vecteur \(\overrightarrow{AB}\)</strong> est caractérisé par <strong>trois éléments</strong> :</p>
<div class="def-chips">
<div class="def-chip">
<span class="chip-icon">📐</span>
<div>
<div class="chip-label">Direction</div>
<div class="chip-value">La droite qui porte le vecteur (son inclinaison)</div>
</div>
</div>
<div class="def-chip">
<span class="chip-icon">➡️</span>
<div>
<div class="chip-label">Sens</div>
<div class="chip-value">Le côté vers lequel pointe la flèche (de A vers B)</div>
</div>
</div>
<div class="def-chip">
<span class="chip-icon">📏</span>
<div>
<div class="chip-label">Norme (longueur)</div>
<div class="chip-value">La longueur de la flèche, notée $|\overrightarrow{AB}|$</div>
</div>
</div>
</div>
<div class="formula-box" style="margin-top:20px">
La notation correcte d'un vecteur : $$\overrightarrow{AB}$$
Le point $A$ est l'<strong>origine</strong>, le point $B$ est l'<strong>extrémité</strong>.
</div>
<p style="color:var(--muted);font-size:.9rem;margin-top:12px">⚠️ Attention : $\overrightarrow{AB} \neq \overrightarrow{BA}$ — ils ont le même sens de droite, mais des <strong style="color:var(--text)">sens opposés</strong> !</p>
</div>
</section>
<!-- ===== 3. VECTEURS EGAUX ===== -->
<section class="section" id="egaux">
<div class="section-header">
<div class="section-number">3</div>
<div class="section-title">Vecteurs égaux</div>
</div>
<div class="card">
<p>Deux vecteurs sont <strong style="color:var(--accent3)">égaux</strong> s'ils ont la même direction, le même sens et la même norme.</p>
<div class="formula-box">
$\overrightarrow{AB} = \overrightarrow{CD}$ si et seulement si $ABDC$ est un <strong>parallélogramme</strong>
<br><small style="color:var(--muted)">(ou si les deux vecteurs sont nuls)</small>
</div>
</div>
<div class="widget" style="margin-top:16px">
<div class="widget-header">
<span class="widget-title">🔁 Vecteurs égaux — Parallélogramme</span>
<span class="widget-tag">Interactif</span>
</div>
<div class="widget-body">
<p style="color:var(--muted);font-size:.87rem;margin-bottom:12px">Déplace A ou B — C et D sont construits automatiquement pour que $\overrightarrow{AB} = \overrightarrow{CD}$</p>
<canvas id="equalCanvas" width="660" height="320" style="width:100%;height:320px"></canvas>
<div class="info-panel">
<div class="info-item"><span class="info-label">AB</span><span class="info-value blue" id="eqAB">(0, 0)</span></div>
<div class="info-item"><span class="info-label">CD</span><span class="info-value teal" id="eqCD">(0, 0)</span></div>
<div class="info-item"><span class="info-label">Égaux ?</span><span class="info-value green" id="eqStatus" style="color:var(--success)">✓ Oui</span></div>
</div>
</div>
</div>
</section>
<!-- ===== 4. CHASLES ===== -->
<section class="section" id="chasles">
<div class="section-header">
<div class="section-number">4</div>
<div class="section-title">Relation de Chasles</div>
</div>
<div class="card highlight-card">
<h3 style="font-family:'Syne',sans-serif;margin-bottom:12px">📌 Théorème</h3>
<div class="formula-box">
$$\overrightarrow{AC} = \overrightarrow{AB} + \overrightarrow{BC}$$
</div>
<p style="color:var(--muted)">Pour aller de A à C, je peux passer par un point intermédiaire B. Le vecteur $\overrightarrow{AC}$ est la <strong style="color:var(--text)">somme</strong> de $\overrightarrow{AB}$ et $\overrightarrow{BC}$.</p>
<div class="formula-box" style="margin-top:12px;border-color:rgba(255,107,107,.35);background:rgba(255,107,107,.06)">
Conséquence : $\overrightarrow{AB} + \overrightarrow{BA} = \overrightarrow{AA} = \vec{0}$
</div>
</div>
<div class="widget" style="margin-top:16px">
<div class="widget-header">
<span class="widget-title">➕ Visualisation de la relation de Chasles</span>
<span class="widget-tag">Interactif</span>
</div>
<div class="widget-body">
<p style="color:var(--muted);font-size:.87rem;margin-bottom:12px">Déplace A, B ou C pour voir comment $\overrightarrow{AB} + \overrightarrow{BC} = \overrightarrow{AC}$</p>
<canvas id="chaslesCanvas" width="660" height="340" style="width:100%;height:340px"></canvas>
<div class="info-panel">
<div class="info-item"><span class="info-label">AB</span><span class="info-value blue" id="chAB">(0,0)</span></div>
<div class="info-item"><span class="info-label">BC</span><span class="info-value teal" id="chBC">(0,0)</span></div>
<div class="info-item"><span class="info-label">AC = AB + BC</span><span class="info-value" style="color:var(--accent5)" id="chAC">(0,0)</span></div>
<div class="info-item"><span class="info-label">|AC|</span><span class="info-value gold" id="chNorm">0</span></div>
</div>
</div>
</div>
</section>
<!-- ===== 5. COORDONNEES ===== -->
<section class="section" id="coordonnees">
<div class="section-header">
<div class="section-number">5</div>
<div class="section-title">Coordonnées d'un vecteur</div>
</div>
<div class="card">
<p>Dans un repère, si $A(x_A ; y_A)$ et $B(x_B ; y_B)$, alors :</p>
<div class="formula-box">
$$\overrightarrow{AB} = \begin{pmatrix} x_B - x_A \\ y_B - y_A \end{pmatrix}$$
</div>
<p style="color:var(--muted);margin-top:8px">Exemple : si $A(2\,;\,1)$ et $B(5\,;\,4)$, alors $\overrightarrow{AB} = \begin{pmatrix} 3 \\ 3 \end{pmatrix}$</p>
</div>
<div class="widget" style="margin-top:16px">
<div class="widget-header">
<span class="widget-title">📊 Repère interactif avec coordonnées</span>
<span class="widget-tag">Interactif</span>
</div>
<div class="widget-body">
<canvas id="coordCanvas" width="660" height="360" style="width:100%;height:360px"></canvas>
<div class="info-panel">
<div class="info-item"><span class="info-label">A</span><span class="info-value blue" id="coordA">(0, 0)</span></div>
<div class="info-item"><span class="info-label">B</span><span class="info-value teal" id="coordB">(0, 0)</span></div>
<div class="info-item"><span class="info-label">$x_B - x_A$</span><span class="info-value gold" id="coordDx">0</span></div>
<div class="info-item"><span class="info-label">$y_B - y_A$</span><span class="info-value" style="color:var(--accent5)" id="coordDy">0</span></div>
<div class="info-item"><span class="info-label">Vecteur</span><span class="info-value red" id="coordVec">(0; 0)</span></div>
</div>
</div>
</div>
</section>
<!-- ===== 6. NORME ===== -->
<section class="section" id="norme">
<div class="section-header">
<div class="section-number">6</div>
<div class="section-title">Norme d'un vecteur</div>
</div>
<div class="card highlight-card">
<div class="formula-box">
$$\left|\overrightarrow{AB}\right| = \sqrt{(x_B - x_A)^2 + (y_B - y_A)^2}$$
</div>
<p style="color:var(--muted);margin-top:8px">C'est simplement la <strong style="color:var(--text)">distance</strong> entre A et B — le théorème de Pythagore !</p>
</div>
<div class="card" style="margin-top:16px">
<h4 style="font-family:'Syne',sans-serif;margin-bottom:12px">Exemple de calcul</h4>
<p>Soit $A(1\,;\,2)$ et $B(4\,;\,6)$. Calcule $|\overrightarrow{AB}|$.</p>
<div class="formula-box" style="margin-top:12px;text-align:left">
$\overrightarrow{AB} = \begin{pmatrix} 4-1 \\ 6-2 \end{pmatrix} = \begin{pmatrix} 3 \\ 4 \end{pmatrix}$
<br><br>
$|\overrightarrow{AB}| = \sqrt{3^2 + 4^2} = \sqrt{9+16} = \sqrt{25} = 5$
</div>
</div>
<!-- Calculatrice de norme -->
<div class="card" style="margin-top:16px">
<h4 style="font-family:'Syne',sans-serif;margin-bottom:14px">🧮 Calculatrice de norme</h4>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px">
<div><label style="font-size:.8rem;color:var(--muted);display:block;margin-bottom:5px">$x_A$</label><input type="number" id="nxA" value="1" class="answer-input" style="margin:0"></div>
<div><label style="font-size:.8rem;color:var(--muted);display:block;margin-bottom:5px">$y_A$</label><input type="number" id="nyA" value="2" class="answer-input" style="margin:0"></div>
<div><label style="font-size:.8rem;color:var(--muted);display:block;margin-bottom:5px">$x_B$</label><input type="number" id="nxB" value="4" class="answer-input" style="margin:0"></div>
<div><label style="font-size:.8rem;color:var(--muted);display:block;margin-bottom:5px">$y_B$</label><input type="number" id="nyB" value="6" class="answer-input" style="margin:0"></div>
</div>
<button class="btn btn-primary" onclick="calcNorme()" style="margin-top:14px">Calculer</button>
<div id="normeResult" style="margin-top:14px;padding:14px;border-radius:10px;background:var(--surface);display:none;font-size:.95rem"></div>
</div>
</section>
<!-- ===== 7. GEOGEBRA ===== -->
<section class="section" id="geogebra">
<div class="section-header">
<div class="section-number">7</div>
<div class="section-title">Exploration GeoGebra</div>
</div>
<div class="card">
<p style="margin-bottom:16px;color:var(--muted)">Manipule directement les vecteurs dans cet applet GeoGebra — déplace les points, observe les propriétés !</p>
<div class="ggb-wrap">
<iframe
src="https://www.geogebra.org/material/iframe/id/rfhq44kb/width/800/height/480/border/888888/sfsb/true/smb/false/stb/false/stbh/false/ai/false/asb/false/sri/true/rc/false/ld/false/sdz/true/ctl/false"
width="800"
height="480"
style="width:100%"
allowfullscreen
title="GeoGebra — Vecteurs interactifs">
</iframe>
</div>
<p style="margin-top:12px;font-size:.82rem;color:var(--muted)">💡 Tip : déplace les points directement dans l'applet pour explorer la relation de Chasles.</p>
</div>
</section>
<!-- ===== 8. EXERCICES ===== -->
<section class="section" id="exercices">
<div class="section-header">
<div class="section-number">8</div>
<div class="section-title">Exercices interactifs</div>
</div>
<!-- Ex 1 -->
<div class="exercise">
<div class="exercise-num">Exercice 1 — Coordonnées</div>
<h4>Calcule les coordonnées du vecteur $\overrightarrow{AB}$</h4>
<p>On donne $A(3\,;\,1)$ et $B(7\,;\,5)$.</p>
<p style="margin-top:8px">Donne la valeur de $x_B - x_A$ (la première coordonnée) :</p>
<input type="number" id="ex1" class="answer-input" placeholder="Votre réponse..." oninput="checkEx1()">
<div id="fb1" class="feedback"></div>
</div>
<!-- Ex 2 -->
<div class="exercise">
<div class="exercise-num">Exercice 2 — Norme</div>
<h4>Calcule la norme du vecteur $\overrightarrow{AB}$</h4>
<p>On donne $A(0\,;\,0)$ et $B(3\,;\,4)$. Quelle est la norme de $\overrightarrow{AB}$ ?</p>
<input type="number" id="ex2" class="answer-input" placeholder="Votre réponse..." oninput="checkEx2()">
<div id="fb2" class="feedback"></div>
</div>
<!-- Ex 3 -->
<div class="exercise">
<div class="exercise-num">Exercice 3 — Relation de Chasles</div>
<h4>Simplifie l'expression suivante :</h4>
<p>Soit $\overrightarrow{AB} + \overrightarrow{BC} = ?$</p>
<div style="display:flex;flex-wrap:wrap;gap:10px;margin-top:12px">
<button class="btn btn-ghost" onclick="checkEx3('AB')">$\overrightarrow{AB}$</button>
<button class="btn btn-ghost" onclick="checkEx3('AC')">$\overrightarrow{AC}$</button>
<button class="btn btn-ghost" onclick="checkEx3('BC')">$\overrightarrow{BC}$</button>
<button class="btn btn-ghost" onclick="checkEx3('0')">$\vec{0}$</button>
</div>
<div id="fb3" class="feedback"></div>
</div>
<!-- Ex 4 -->
<div class="exercise">
<div class="exercise-num">Exercice 4 — Vecteurs égaux</div>
<h4>Vrai ou Faux ?</h4>
<p>$\overrightarrow{AB}$ et $\overrightarrow{BA}$ sont des vecteurs égaux.</p>
<div style="display:flex;gap:10px;margin-top:12px">
<button class="btn btn-ghost" onclick="checkEx4(true)">✓ Vrai</button>
<button class="btn btn-ghost" onclick="checkEx4(false)">✗ Faux</button>
</div>
<div id="fb4" class="feedback"></div>
</div>
<!-- Ex 5 -->
<div class="exercise">
<div class="exercise-num">Exercice 5 — Chasles avancé</div>
<h4>Complète la relation de Chasles</h4>
<p>$\overrightarrow{AC} - \overrightarrow{BC} = ?$</p>
<div style="display:flex;flex-wrap:wrap;gap:10px;margin-top:12px">
<button class="btn btn-ghost" onclick="checkEx5('AB')">$\overrightarrow{AB}$</button>
<button class="btn btn-ghost" onclick="checkEx5('BC')">$\overrightarrow{BC}$</button>
<button class="btn btn-ghost" onclick="checkEx5('CA')">$\overrightarrow{CA}$</button>
<button class="btn btn-ghost" onclick="checkEx5('0')">$\vec{0}$</button>
</div>
<div id="fb5" class="feedback"></div>
</div>
</section>
<!-- ===== 9. MODE PROF ===== -->
<section class="section" id="prof">
<div class="section-header">
<div class="section-number">9</div>
<div class="section-title">Mode Professeur</div>
</div>
<div class="prof-mode widget">
<div class="prof-header">
<span class="prof-badge">👩🏫 PROF</span>
<span style="font-family:'Syne',sans-serif;font-weight:700">Tableau de démonstration libre</span>
</div>
<div class="prof-tools">
<!-- Tool buttons -->
<button class="tool-btn active" id="toolDraw" onclick="setProfTool('draw')">✏️ Dessiner</button>
<button class="tool-btn" id="toolVector" onclick="setProfTool('vector')">➡️ Vecteur</button>
<button class="tool-btn" id="toolPoint" onclick="setProfTool('point')">📍 Point</button>
<button class="tool-btn" id="toolText" onclick="setProfTool('text')">🔤 Texte</button>
<div style="width:1px;height:28px;background:var(--border)"></div>
<!-- Color row -->
<div class="color-row">
<div class="color-dot active" style="background:#5b8fff" onclick="setProfColor('#5b8fff',this)"></div>
<div class="color-dot" style="background:#ff6b6b" onclick="setProfColor('#ff6b6b',this)"></div>
<div class="color-dot" style="background:#4ecdc4" onclick="setProfColor('#4ecdc4',this)"></div>
<div class="color-dot" style="background:#ffd166" onclick="setProfColor('#ffd166',this)"></div>
<div class="color-dot" style="background:#ffffff" onclick="setProfColor('#ffffff',this)"></div>
<div class="color-dot" style="background:#a29bfe" onclick="setProfColor('#a29bfe',this)"></div>
</div>
<div style="width:1px;height:28px;background:var(--border)"></div>
<label style="font-size:.8rem;color:var(--muted);display:flex;align-items:center;gap:8px">
Épaisseur <input type="range" id="profSize" min="1" max="12" value="3">
</label>
<div style="margin-left:auto;display:flex;gap:8px">
<button class="btn btn-ghost" onclick="undoProf()">↩️ Annuler</button>
<button class="btn btn-danger" onclick="clearProf()">🗑️ Effacer tout</button>
</div>
</div>
<div style="padding:16px">
<canvas id="profCanvas" width="800" height="500" style="width:100%;height:500px;cursor:crosshair"></canvas>
</div>
<div style="padding:10px 16px;border-top:1px solid var(--border);font-size:.8rem;color:var(--muted)">
💡 Clic + glisser pour dessiner · Mode Vecteur : cliquer le point de départ puis l'extrémité · Mode Point : cliquer pour placer
</div>
</div>
</section>
</main>
<!-- ===== FOOTER ===== -->
<footer style="text-align:center;padding:40px 20px;border-top:1px solid var(--border);color:var(--muted);font-size:.85rem">
<p>Capsule interactive Vecteurs · 3ème · Mathématiques</p>
<p style="margin-top:4px;font-size:.78rem;opacity:.6">Conçu pour être utilisé en classe ou en autonomie</p>
</footer>
<!-- ===== JAVASCRIPT ===== -->
<script>
/* ============================================================
UTILITAIRES CANVAS COMMUNES
============================================================ */
// Dessiner une flèche sur canvas
function drawArrow(ctx, x1,y1,x2,y2, color='#5b8fff', width=2.5, label='', labelColor='') {
const dx = x2-x1, dy = y2-y1;
const len = Math.hypot(dx,dy);
if (len < 2) return;
const angle = Math.atan2(dy,dx);
const headLen = Math.min(18, len*0.35);
ctx.save();
ctx.strokeStyle = color;
ctx.fillStyle = color;
ctx.lineWidth = width;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
// arrowhead
ctx.beginPath();
ctx.moveTo(x2, y2);
ctx.lineTo(x2 - headLen*Math.cos(angle-0.42), y2 - headLen*Math.sin(angle-0.42));
ctx.lineTo(x2 - headLen*Math.cos(angle+0.42), y2 - headLen*Math.sin(angle+0.42));
ctx.closePath();
ctx.fill();
// label
if (label) {
ctx.font = 'bold 13px Syne, sans-serif';
ctx.fillStyle = labelColor || color;
const mx = (x1+x2)/2 - 14*Math.sin(angle);
const my = (y1+y2)/2 + 14*Math.cos(angle);
ctx.fillText(label, mx, my);
}
ctx.restore();
}
function drawPoint(ctx, x, y, color='#fff', radius=6, label='', labelOffset={x:10,y:-10}) {
ctx.save();
ctx.beginPath();
ctx.arc(x,y,radius,0,Math.PI*2);
ctx.fillStyle = color;
ctx.fill();
ctx.strokeStyle = 'rgba(0,0,0,.4)';
ctx.lineWidth = 1.5;
ctx.stroke();
if (label) {
ctx.font = 'bold 14px Syne, sans-serif';
ctx.fillStyle = color;
ctx.fillText(label, x+labelOffset.x, y+labelOffset.y);
}
ctx.restore();
}
function drawGrid(ctx, w, h, step=40, originX, originY) {
ctx.save();
ctx.strokeStyle = 'rgba(255,255,255,.05)';
ctx.lineWidth = 1;
for (let x=0; x<w; x+=step) { ctx.beginPath(); ctx.moveTo(x,0); ctx.lineTo(x,h); ctx.stroke(); }
for (let y=0; y<h; y+=step) { ctx.beginPath(); ctx.moveTo(0,y); ctx.lineTo(w,y); ctx.stroke(); }
// axes
if (originX !== undefined) {
ctx.strokeStyle = 'rgba(255,255,255,.25)';
ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.moveTo(0,originY); ctx.lineTo(w,originY); ctx.stroke();
ctx.beginPath(); ctx.moveTo(originX,0); ctx.lineTo(originX,h); ctx.stroke();
// ticks and labels
ctx.fillStyle = 'rgba(255,255,255,.35)';
ctx.font = '10px DM Sans';
for (let x=originX; x<w; x+=step) {
const val = Math.round((x-originX)/step);
if (val!==0) ctx.fillText(val, x-4, originY+14);
ctx.beginPath(); ctx.moveTo(x,originY-3); ctx.lineTo(x,originY+3); ctx.stroke();
}
for (let x=originX; x>0; x-=step) {
const val = Math.round((x-originX)/step);
ctx.fillText(val, x-8, originY+14);
ctx.beginPath(); ctx.moveTo(x,originY-3); ctx.lineTo(x,originY+3); ctx.stroke();
}
for (let y=originY; y<h; y+=step) {
const val = -Math.round((y-originY)/step);
if (val!==0) ctx.fillText(val, originX-20, y+4);
ctx.beginPath(); ctx.moveTo(originX-3,y); ctx.lineTo(originX+3,y); ctx.stroke();
}
for (let y=originY; y>0; y-=step) {
const val = -Math.round((y-originY)/step);
ctx.fillText(val, originX-20, y+4);
ctx.beginPath(); ctx.moveTo(originX-3,y); ctx.lineTo(originX+3,y); ctx.stroke();
}
ctx.fillStyle='rgba(255,255,255,.5)';ctx.font='bold 12px Syne';
ctx.fillText('x',w-16,originY-8);
ctx.fillText('y',originX+8,12);
ctx.fillText('O',originX+5,originY+14);
}
ctx.restore();
}
// drag helper
function makeDraggable(canvas, points, onUpdate) {
let drag = null;
const rect = () => canvas.getBoundingClientRect();
const pos = (e) => {
const r = rect();
const scaleX = canvas.width / r.width;
const scaleY = canvas.height / r.height;
const src = e.touches ? e.touches[0] : e;
return { x: (src.clientX - r.left)*scaleX, y: (src.clientY - r.top)*scaleY };
};
const start = (e) => {
e.preventDefault();
const p = pos(e);
let best = null, bestD = 999;
points.forEach((pt,i) => {
const d = Math.hypot(pt.x-p.x, pt.y-p.y);
if (d < 20 && d < bestD) { bestD=d; best=i; }
});
drag = best;
};
const move = (e) => {
e.preventDefault();
if (drag===null) return;
const p = pos(e);
points[drag].x = Math.max(16, Math.min(canvas.width-16, p.x));
points[drag].y = Math.max(16, Math.min(canvas.height-16, p.y));
onUpdate();
};
const end = () => { drag=null; };
canvas.addEventListener('mousedown', start);
canvas.addEventListener('mousemove', move);
canvas.addEventListener('mouseup', end);
canvas.addEventListener('touchstart', start, {passive:false});
canvas.addEventListener('touchmove', move, {passive:false});
canvas.addEventListener('touchend', end);
}
/* ============================================================
WIDGET 1 — INTRO (vecteur AB déplaçable)
============================================================ */
(function() {
const canvas = document.getElementById('introCanvas');
const ctx = canvas.getContext('2d');
const W = canvas.width, H = canvas.height;
const pts = [{x:200,y:200},{x:450,y:120}];
function draw() {
ctx.clearRect(0,0,W,H);
drawGrid(ctx,W,H,40);
// glow effect on vector
ctx.save();
ctx.shadowColor = '#5b8fff';
ctx.shadowBlur = 18;
drawArrow(ctx, pts[0].x, pts[0].y, pts[1].x, pts[1].y, '#5b8fff', 3, '');
ctx.restore();
drawPoint(ctx, pts[0].x, pts[0].y, '#ff6b6b', 7, 'A', {x:-18,y:-10});
drawPoint(ctx, pts[1].x, pts[1].y, '#4ecdc4', 7, 'B', {x:10,y:-10});
const dx = pts[1].x - pts[0].x, dy = pts[1].y - pts[0].y;
const norm = Math.hypot(dx,dy).toFixed(1);
const angle = (Math.atan2(dy,dx)*180/Math.PI).toFixed(1);
document.getElementById('introCoord').textContent = `(${dx.toFixed(0)} ; ${(-dy).toFixed(0)})`;
document.getElementById('introNorm').textContent = norm + ' px';
document.getElementById('introAngle').textContent = angle + '°';
}
makeDraggable(canvas, pts, draw);
draw();
})();
/* ============================================================
WIDGET 2 — VECTEURS EGAUX
============================================================ */
(function() {
const canvas = document.getElementById('equalCanvas');
const ctx = canvas.getContext('2d');
const W = canvas.width, H = canvas.height;
// A, B déplaçables; offset de C par rapport à A
const pts = [{x:180,y:240},{x:340,y:160}];
const offset = {x:100, y:80};
function draw() {
ctx.clearRect(0,0,W,H);
drawGrid(ctx,W,H,40);
const A=pts[0], B=pts[1];
const C={x:A.x+offset.x, y:A.y+offset.y};
const D={x:B.x+offset.x, y:B.y+offset.y};
// parallélogramme fill
ctx.save();
ctx.beginPath();
ctx.moveTo(A.x,A.y); ctx.lineTo(B.x,B.y); ctx.lineTo(D.x,D.y); ctx.lineTo(C.x,C.y);
ctx.closePath();
ctx.fillStyle = 'rgba(91,143,255,.07)';
ctx.fill();
ctx.strokeStyle = 'rgba(91,143,255,.25)';
ctx.setLineDash([5,5]);
ctx.lineWidth = 1.2;
ctx.stroke();
ctx.restore();
ctx.save(); ctx.shadowColor='#5b8fff'; ctx.shadowBlur=14;
drawArrow(ctx,A.x,A.y,B.x,B.y,'#5b8fff',3,'AB⃗');
ctx.restore();
ctx.save(); ctx.shadowColor='#4ecdc4'; ctx.shadowBlur=14;
drawArrow(ctx,C.x,C.y,D.x,D.y,'#4ecdc4',3,'CD⃗');
ctx.restore();
drawPoint(ctx,A.x,A.y,'#ff6b6b',6,'A',{x:-18,y:-10});
drawPoint(ctx,B.x,B.y,'#ff6b6b',6,'B',{x:10,y:-10});
drawPoint(ctx,C.x,C.y,'#4ecdc4',6,'C',{x:-18,y:12});
drawPoint(ctx,D.x,D.y,'#4ecdc4',6,'D',{x:10,y:12});
const dx=B.x-A.x, dy=B.y-A.y;
document.getElementById('eqAB').textContent=`(${dx.toFixed(0)} ; ${(-dy).toFixed(0)})`;
document.getElementById('eqCD').textContent=`(${dx.toFixed(0)} ; ${(-dy).toFixed(0)})`;
}
makeDraggable(canvas, pts, draw);
// also allow dragging offset via C
let dragOff = false;
const r = () => canvas.getBoundingClientRect();
const pos = e => {
const rc = r(); const scaleX=canvas.width/rc.width; const scaleY=canvas.height/rc.height;
const src = e.touches?e.touches[0]:e;
return {x:(src.clientX-rc.left)*scaleX, y:(src.clientY-rc.top)*scaleY};
};
canvas.addEventListener('mousedown', e => {
const p=pos(e); const C={x:pts[0].x+offset.x,y:pts[0].y+offset.y};
if (Math.hypot(C.x-p.x,C.y-p.y)<20) dragOff=true;
});
canvas.addEventListener('mousemove', e => {
if (!dragOff) return;
const p=pos(e);
offset.x=p.x-pts[0].x; offset.y=p.y-pts[0].y;
draw();
});
canvas.addEventListener('mouseup',()=>{dragOff=false;});
draw();
})();
/* ============================================================
WIDGET 3 — CHASLES
============================================================ */
(function() {
const canvas = document.getElementById('chaslesCanvas');
const ctx = canvas.getContext('2d');
const W=canvas.width, H=canvas.height;
const pts=[{x:130,y:260},{x:340,y:150},{x:540,y:240}];
function draw() {
ctx.clearRect(0,0,W,H);
drawGrid(ctx,W,H,40);
const [A,B,C]=pts;
// AC en arrière-plan
ctx.save(); ctx.shadowColor='#a29bfe'; ctx.shadowBlur=20; ctx.globalAlpha=.7;
drawArrow(ctx,A.x,A.y,C.x,C.y,'#a29bfe',3.5,'AC⃗');
ctx.restore();
// AB
ctx.save(); ctx.shadowColor='#5b8fff'; ctx.shadowBlur=16;
drawArrow(ctx,A.x,A.y,B.x,B.y,'#5b8fff',3,'AB⃗');
ctx.restore();
// BC
ctx.save(); ctx.shadowColor='#4ecdc4'; ctx.shadowBlur=16;
drawArrow(ctx,B.x,B.y,C.x,C.y,'#4ecdc4',3,'BC⃗');
ctx.restore();
drawPoint(ctx,A.x,A.y,'#ff6b6b',7,'A',{x:-18,y:-10});
drawPoint(ctx,B.x,B.y,'#5b8fff',7,'B',{x:10,y:-10});
drawPoint(ctx,C.x,C.y,'#4ecdc4',7,'C',{x:10,y:8});
const abx=B.x-A.x, aby=B.y-A.y;
const bcx=C.x-B.x, bcy=C.y-B.y;
const acx=C.x-A.x, acy=C.y-A.y;
const norm=Math.hypot(acx,acy).toFixed(1);
document.getElementById('chAB').textContent=`(${abx.toFixed(0)} ; ${(-aby).toFixed(0)})`;
document.getElementById('chBC').textContent=`(${bcx.toFixed(0)} ; ${(-bcy).toFixed(0)})`;
document.getElementById('chAC').textContent=`(${acx.toFixed(0)} ; ${(-acy).toFixed(0)})`;
document.getElementById('chNorm').textContent=norm+' px';
}
makeDraggable(canvas,pts,draw);
draw();
})();
/* ============================================================
WIDGET 4 — REPERE + COORDONNEES
============================================================ */
(function() {
const canvas = document.getElementById('coordCanvas');
const ctx = canvas.getContext('2d');
const W=canvas.width, H=canvas.height;
const step=40, ox=Math.round(W/2), oy=Math.round(H/2);
const pts=[{x:ox-80,y:oy+40},{x:ox+100,y:oy-80}];
function toPx(mx,my){return{x:ox+mx*step,y:oy-my*step};}
function toMath(px,py){return{x:(px-ox)/step,y:-(py-oy)/step};}
function draw() {
ctx.clearRect(0,0,W,H);
drawGrid(ctx,W,H,step,ox,oy);
const A=pts[0], B=pts[1];
// dashed horizontal/vertical lines
ctx.save();
ctx.setLineDash([4,4]);
ctx.strokeStyle='rgba(255,255,255,.18)';
ctx.lineWidth=1;
ctx.beginPath(); ctx.moveTo(A.x,A.y); ctx.lineTo(B.x,A.y); ctx.stroke();
ctx.beginPath(); ctx.moveTo(B.x,A.y); ctx.lineTo(B.x,B.y); ctx.stroke();
ctx.restore();
ctx.save(); ctx.shadowColor='#5b8fff'; ctx.shadowBlur=18;
drawArrow(ctx,A.x,A.y,B.x,B.y,'#5b8fff',3,'AB⃗');
ctx.restore();
drawPoint(ctx,A.x,A.y,'#ff6b6b',7,'A',{x:-18,y:-10});
drawPoint(ctx,B.x,B.y,'#4ecdc4',7,'B',{x:10,y:-10});
const ma=toMath(A.x,A.y), mb=toMath(B.x,B.y);
const dx=mb.x-ma.x, dy=mb.y-ma.y;
document.getElementById('coordA').textContent=`(${ma.x.toFixed(1)} ; ${ma.y.toFixed(1)})`;
document.getElementById('coordB').textContent=`(${mb.x.toFixed(1)} ; ${mb.y.toFixed(1)})`;
document.getElementById('coordDx').textContent=dx.toFixed(2);
document.getElementById('coordDy').textContent=dy.toFixed(2);
document.getElementById('coordVec').textContent=`(${dx.toFixed(2)} ; ${dy.toFixed(2)})`;
}
makeDraggable(canvas,pts,draw);
draw();
})();
/* ============================================================
CALCULATRICE DE NORME
============================================================ */
function calcNorme() {
const xa=+document.getElementById('nxA').value;
const ya=+document.getElementById('nyA').value;
const xb=+document.getElementById('nxB').value;
const yb=+document.getElementById('nyB').value;
const dx=xb-xa, dy=yb-ya;
const norm=Math.sqrt(dx*dx+dy*dy);
const el=document.getElementById('normeResult');
el.style.display='block';
el.innerHTML=`
<strong style="color:var(--accent1)">Calcul détaillé :</strong><br>
\\[\\overrightarrow{AB} = \\begin{pmatrix} ${xb}-${xa} \\\\ ${yb}-${ya} \\end{pmatrix} = \\begin{pmatrix} ${dx} \\\\ ${dy} \\end{pmatrix}\\]
\\[|\\overrightarrow{AB}| = \\sqrt{(${dx})^2 + (${dy})^2} = \\sqrt{${dx*dx}+${dy*dy}} = \\sqrt{${dx*dx+dy*dy}} \\approx \\color{#ffd166}{${norm.toFixed(3)}}\\]
`;
MathJax.typesetPromise([el]);
}
/* ============================================================
EXERCICES — VÉRIFICATIONS
============================================================ */
function checkEx1() {
const v=+document.getElementById('ex1').value;
const fb=document.getElementById('fb1');
if(v===4){fb.className='feedback correct';fb.textContent='✓ Bravo ! x_B - x_A = 7 - 3 = 4';}
else{fb.className='feedback wrong';fb.textContent='✗ Réessaie… Calcule 7 - 3.';}
}
function checkEx2() {
const v=+document.getElementById('ex2').value;
const fb=document.getElementById('fb2');
if(v===5){fb.className='feedback correct';fb.textContent='✓ Parfait ! √(3² + 4²) = √25 = 5';}
else{fb.className='feedback wrong';fb.textContent='✗ Calcule √(3² + 4²). Pense au théorème de Pythagore !';}
}
function checkEx3(ans) {
const fb=document.getElementById('fb3');
if(ans==='AC'){fb.className='feedback correct';fb.textContent='✓ Excellent ! C\'est bien AC⃗ — c\'est la relation de Chasles !';}
else{fb.className='feedback wrong';fb.textContent='✗ Relis la relation de Chasles : AB⃗ + BC⃗ = AC⃗';}
}
function checkEx4(ans) {
const fb=document.getElementById('fb4');
if(!ans){fb.className='feedback correct';fb.textContent='✓ Correct ! AB⃗ et BA⃗ ont des sens opposés, donc ils ne sont pas égaux (sauf si nul).';}
else{fb.className='feedback wrong';fb.textContent='✗ Non ! AB⃗ va de A vers B, BA⃗ va de B vers A — sens opposés !';}
}
function checkEx5(ans) {
const fb=document.getElementById('fb5');
if(ans==='AB'){fb.className='feedback correct';fb.textContent='✓ Bravo ! AC⃗ - BC⃗ = AC⃗ + CB⃗ = AB⃗ (Chasles)';}
else{fb.className='feedback wrong';fb.textContent='✗ Rappel : soustraire BC⃗ = ajouter CB⃗, puis AC⃗ + CB⃗ = AB⃗';}
}
/* ============================================================
MODE PROFESSEUR
============================================================ */
(function() {
const canvas=document.getElementById('profCanvas');
const ctx=canvas.getContext('2d');
const W=canvas.width, H=canvas.height;
let tool='draw', color='#5b8fff', size=3;
let drawing=false, startX=0, startY=0;
let history=[], snapshot=null;
// init background
function initBg() {
ctx.fillStyle='#0f1220';
ctx.fillRect(0,0,W,H);
drawGrid(ctx,W,H,40,W/2,H/2);
}
initBg();
window.setProfTool = function(t) {
tool=t;
document.querySelectorAll('.tool-btn').forEach(b=>b.classList.remove('active'));
document.getElementById('tool'+t.charAt(0).toUpperCase()+t.slice(1))?.classList.add('active');
};
window.setProfColor = function(c, el) {
color=c;
document.querySelectorAll('.color-dot').forEach(d=>d.classList.remove('active'));
el.classList.add('active');
};
document.getElementById('profSize').addEventListener('input', e => { size=+e.target.value; });
function saveHistory() { history.push(canvas.toDataURL()); if(history.length>40) history.shift(); }
window.undoProf = function() {
if(!history.length) return;
const img=new Image();
img.src=history.pop();
img.onload=()=>ctx.drawImage(img,0,0);
};
window.clearProf = function() {
saveHistory();
ctx.clearRect(0,0,W,H);
initBg();
};
const rc=()=>canvas.getBoundingClientRect();
const pos=e=>{
const r=rc(); const scaleX=canvas.width/r.width; const scaleY=canvas.height/r.height;
const src=e.touches?e.touches[0]:e;
return {x:(src.clientX-r.left)*scaleX,y:(src.clientY-r.top)*scaleY};
};
canvas.addEventListener('mousedown', e=>{
drawing=true;
const p=pos(e); startX=p.x; startY=p.y;
saveHistory();
if(tool==='point'){
drawPoint(ctx,p.x,p.y,color,6,'','');
// label dialog
const lbl=prompt('Nom du point (optionnel):','P');
if(lbl) {
ctx.font=`bold 14px Syne,sans-serif`;
ctx.fillStyle=color;
ctx.fillText(lbl,p.x+10,p.y-10);
}
drawing=false;
}
if(tool==='text'){
const txt=prompt('Texte à ajouter:','');
if(txt){
ctx.font=`${size*4+10}px DM Sans,sans-serif`;
ctx.fillStyle=color;
ctx.fillText(txt,p.x,p.y);
}
drawing=false;
}
if(tool==='draw') {
snapshot=ctx.getImageData(0,0,W,H);
ctx.beginPath(); ctx.moveTo(p.x,p.y);
}
if(tool==='vector') snapshot=ctx.getImageData(0,0,W,H);
});
canvas.addEventListener('mousemove', e=>{
if(!drawing) return;
const p=pos(e);
if(tool==='draw') {
ctx.strokeStyle=color;
ctx.lineWidth=size;
ctx.lineCap='round';
ctx.lineJoin='round';
ctx.lineTo(p.x,p.y);
ctx.stroke();
ctx.beginPath(); ctx.moveTo(p.x,p.y);
}
if(tool==='vector' && snapshot) {
ctx.putImageData(snapshot,0,0);
drawArrow(ctx,startX,startY,p.x,p.y,color,size+1);
}
});
canvas.addEventListener('mouseup', e=>{
if(!drawing) return;
drawing=false;
const p=pos(e);
if(tool==='vector') drawArrow(ctx,startX,startY,p.x,p.y,color,size+1);
snapshot=null;
});
canvas.addEventListener('touchstart',e=>{e.preventDefault();canvas.dispatchEvent(new MouseEvent('mousedown',{clientX:e.touches[0].clientX,clientY:e.touches[0].clientY}));},{passive:false});
canvas.addEventListener('touchmove',e=>{e.preventDefault();canvas.dispatchEvent(new MouseEvent('mousemove',{clientX:e.touches[0].clientX,clientY:e.touches[0].clientY}));},{passive:false});
canvas.addEventListener('touchend',e=>{canvas.dispatchEvent(new MouseEvent('mouseup',{}));});
})();
/* ============================================================
SCROLL ANIMATIONS + PROGRESS BAR
============================================================ */
const sections = document.querySelectorAll('.section');
const obs = new IntersectionObserver(entries => {
entries.forEach(e=>{ if(e.isIntersecting) e.target.classList.add('visible'); });
},{threshold:0.08});
sections.forEach(s=>obs.observe(s));
window.addEventListener('scroll',()=>{
const scrollTop=window.scrollY||document.documentElement.scrollTop;
const docH=document.documentElement.scrollHeight-window.innerHeight;
document.getElementById('progress-bar').style.width=(scrollTop/docH*100)+'%';
});
</script>
</body>
</html>17
6
3053KB
9078KB
1,598.0ms
200.0ms
3,192.0ms