Compare commits

...

2 commits

Author SHA1 Message Date
97359d172b rename & handle several canvas 2026-03-15 17:28:39 +01:00
221bc4a1c4 handle size of datas 2026-03-13 01:40:30 +01:00
7 changed files with 193 additions and 143 deletions

View file

@ -1,28 +1,29 @@
<script> <script>
const nombresChinois = [ const nombresChinois = [
{ valeur: 1, hanzi: "一", pinyin: "yī" }, { valeur: 1, hanzi: "一", pinyin: "yī" },
{ valeur: 2, hanzi: "二", pinyin: "èr" }, { valeur: 2, hanzi: "二", pinyin: "èr" },
{ valeur: 3, hanzi: "三", pinyin: "sān" }, { valeur: 3, hanzi: "三", pinyin: "sān" },
{ valeur: 4, hanzi: "四", pinyin: "sì" }, { valeur: 4, hanzi: "四", pinyin: "sì" },
{ valeur: 5, hanzi: "五", pinyin: "wǔ" }, { valeur: 5, hanzi: "五", pinyin: "wǔ" },
{ valeur: 6, hanzi: "六", pinyin: "liù" }, { valeur: 6, hanzi: "六", pinyin: "liù" },
{ valeur: 7, hanzi: "七", pinyin: "qī" }, { valeur: 7, hanzi: "七", pinyin: "qī" },
{ valeur: 8, hanzi: "八", pinyin: "bā" }, { valeur: 8, hanzi: "八", pinyin: "bā" },
{ valeur: 9, hanzi: "九", pinyin: "jiǔ" }, { valeur: 9, hanzi: "九", pinyin: "jiǔ" },
{ valeur: 10, hanzi: "十", pinyin: "shí" } { valeur: 10, hanzi: "十", pinyin: "shí" },
]; { valeur: 11, hanzi: "十一", pinyin: "shíyī" }
];
const pronomsChinois = [ const pronomsChinois = [
{ hanzi: "我", pinyin: "wǒ", valeur: "je / moi" }, { hanzi: "我", pinyin: "wǒ", francais: "je / moi" },
{ hanzi: "你", pinyin: "nǐ", valeur: "tu / toi" }, { hanzi: "你", pinyin: "nǐ", francais: "tu / toi" },
{ hanzi: "您", pinyin: "nín", valeur: "vous (politesse)" }, { hanzi: "您", pinyin: "nín", francais: "vous (politesse)" },
{ hanzi: "他", pinyin: "tā", valeur: "il / lui" }, { hanzi: "他", pinyin: "tā", francais: "il / lui" },
{ hanzi: "她", pinyin: "tā", valeur: "elle" }, { hanzi: "她", pinyin: "tā", francais: "elle" },
{ hanzi: "它", pinyin: "tā", valeur: "il/elle (objet, animal)" }, { hanzi: "它", pinyin: "tā", francais: "il/elle (objet, animal)" },
{ hanzi: "我们", pinyin: "wǒmen", valeur: "nous" }, { hanzi: "我们", pinyin: "wǒmen", francais: "nous" },
{ hanzi: "你们", pinyin: "nǐmen", valeur: "vous (pluriel)" }, { hanzi: "你们", pinyin: "nǐmen", francais: "vous (pluriel)" },
{ hanzi: "他们", pinyin: "tāmen", valeur: "ils (masculin ou mixte)" }, { hanzi: "他们", pinyin: "tāmen", francais: "ils (masculin ou mixte)" },
{ hanzi: "她们", pinyin: "tāmen", valeur: "elles (féminin)" }, { hanzi: "她们", pinyin: "tāmen", francais: "elles (féminin)" },
{ hanzi: "它们", pinyin: "tāmen", valeur: "ils/elles (objets, animaux)" } { hanzi: "它们", pinyin: "tāmen", francais: "ils/elles (objets, animaux)" }
]; ];
</script> </script>

19
hanzi_1.html Normal file
View file

@ -0,0 +1,19 @@
<div id="challenge"></div>
<div id="canvas" class="hanzi-canvas-container"></div>
<button id="valid">Vérifier</button>
<p id="feedback"></p>
<script>
const module1 = createMyReusableModule();
module1.init({
challengeID: "challenge",
canvasID: "canvas",
feedbackID: "feedback",
button_OK_ID: "valid",
view_settings: {
showCharacter: true,
showOutline: true,
},
datas: nombresChinois
});
</script>

View file

@ -1,19 +0,0 @@
<div id="challenge"></div>
<div id="canvas" style="width:200px; height:200px; margin-bottom:10px; border: 2px; border-style: solid;"></div>
<button id="valid">Vérifier</button>
<p id="feedback"></p>
<script>
const module1 = createMyReusableModule();
module1.init({
challengeID: "challenge",
canvasID: "canvas",
feedbackID: "feedback",
button_OK_ID: "valid",
view_settings: {
showCharacter: true,
showOutline: true,
},
datas: nombresChinois
});
</script>

View file

@ -1,5 +1,5 @@
<div id="challenge1"></div> <div id="challenge1"></div>
<div id="canvas1" style="width:200px; height:200px; margin-bottom:10px; border: 2px; border-style: solid;"></div> <div id="canvas1" class="hanzi-canvas-container"></div>
<button id="valid1">Vérifier</button> <button id="valid1">Vérifier</button>
<p id="feedback1"></p> <p id="feedback1"></p>
<script> <script>

View file

@ -1,11 +1,11 @@
<div id="challenge3"></div> <div id="challenge3"></div>
<div id="canvas3" style="width:200px; height:200px; margin-bottom:10px; border: 2px; border-style: solid;"></div> <div id="canvas3" class="hanzi-canvas-container"></div>
<button id="valid3">Vérifier</button> <button id="valid3">Vérifier</button>
<p id="feedback3"></p> <p id="feedback3"></p>
<script> <script>
const module1 = createMyReusableModule(); const module3 = createMyReusableModule();
module1.init({ module3.init({
challengeID: "challenge3", challengeID: "challenge3",
canvasID: "canvas3", canvasID: "canvas3",
feedbackID: "feedback3", feedbackID: "feedback3",

View file

@ -1,126 +1,158 @@
<script src="https://cdn.jsdelivr.net/npm/hanzi-writer@3.5/dist/hanzi-writer.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/hanzi-writer@3.5/dist/hanzi-writer.min.js"></script>
<script> <script>
function createMyReusableModule() { function createMyReusableModule() {
function init(options = {}) {
// Chaque instance possède son propre état
let iNb = 0; let iNb = 0;
let ok = false; let datas = options.datas;
let hw = null; let datas_length = datas.length;
function init(options = {}) { displayChallenge(
displayChallenge( options.challengeID,
options.challengeID, datas[iNb].valeur,
options.datas[iNb].valeur, datas[iNb].pinyin
options.datas[iNb].pinyin );
);
// Initialisation du writer // --- INITIALISATION MULTICANVAS ---
hw = initHW( let { writers, okArray } = initMultiCanvas(
options.canvasID, options.canvasID,
options.datas[iNb].hanzi, datas[iNb].hanzi,
options.view_settings.showCharacter, options.view_settings
options.view_settings.showOutline );
);
const callback_ok = () => { ok = true; }; startMultiQuiz(writers, okArray);
const callback_nok = () => { ok = false; };
// Lancer le premier quiz const bouton = document.querySelector("#" + options.button_OK_ID);
startQuiz1(hw, callback_ok, callback_nok);
const bouton = document.querySelector("#" + options.button_OK_ID); const handleClick = () => {
const handleClick = () => { let isOK = checkAll(okArray, options.feedbackID);
let isOK = check(ok, options.feedbackID, options.challengeID);
switch (isOK) { switch (isOK) {
case 0: case 0:
// fail // incorrect → rien
break; break;
case 1: case 1:
// success // correct → mot suivant
iNb++; iNb++;
if (iNb > 9) { if (iNb >= datas_length) {
document.getElementById(options.feedbackID).textContent = "Fini !"; document.getElementById(options.feedbackID).textContent = "Fini !";
return -1; return -1;
} }
callback_nok(); displayChallenge(
displayChallenge( options.challengeID,
options.challengeID, datas[iNb].valeur,
options.datas[iNb].valeur, datas[iNb].pinyin
options.datas[iNb].pinyin );
);
nextQuiz( // Réinitialiser les canvas pour le nouveau mot
hw, let res = initMultiCanvas(
options.datas[iNb].hanzi, options.canvasID,
callback_ok, datas[iNb].hanzi,
callback_nok options.view_settings
); );
break; writers = res.writers;
okArray = res.okArray;
default: startMultiQuiz(writers, okArray);
break;
}
};
bouton.addEventListener("click", handleClick); break;
} }
};
bouton.addEventListener("click", handleClick);
}
function displayChallenge(divName, chineseChar, pinyin) { // ---------------------------------------------------------
document.getElementById(divName).textContent = // AFFICHAGE DU CHALLENGE
"Écrire : " + chineseChar + " / " + pinyin; // ---------------------------------------------------------
} function displayChallenge(divName, chineseChar, pinyin) {
document.getElementById(divName).textContent =
"Écrire : " + chineseChar + " / " + pinyin;
}
function initHW(canvasID, currentChar, bShowCharacter, bShowOutline) { // ---------------------------------------------------------
return HanziWriter.create(canvasID, currentChar, { // CRÉATION MULTICANVAS
// ---------------------------------------------------------
function initMultiCanvas(containerID, hanzi, view_settings) {
const chars = [...hanzi]; // "十一" → ["十","一"]
const container = document.getElementById(containerID);
container.innerHTML = ""; // reset
let writers = [];
let okArray = new Array(chars.length).fill(false);
chars.forEach((char, index) => {
const c = document.createElement("div");
c.id = `${containerID}_${index}`;
c.style.display = "inline-block";
c.style.marginRight = "10px";
container.appendChild(c);
const hw = HanziWriter.create(c.id, char, {
width: 150, width: 150,
height: 150, height: 150,
showCharacter: bShowCharacter, showCharacter: view_settings.showCharacter,
showOutline: bShowOutline, showOutline: view_settings.showOutline,
showHintAfterMisses: 1, showHintAfterMisses: 1,
highlightOnComplete: false, highlightOnComplete: false,
padding: 5 padding: 5
}); });
}
function startQuiz1(hw, fbok, fbpok) { writers.push(hw);
fbpok(); // reset });
hw.quiz({ return { writers, okArray };
onMistake: () => fbpok(),
onCorrectStroke: () => { },
onComplete: () => fbok()
});
}
// Return >0 if ok; 0: fail; -1 if finish
function check(ok, feedbackId) {
if (ok) {
document.getElementById(feedbackId).textContent = "✔️ Bravo !";
document.getElementById(feedbackId).style.color = "green";
return 1;
} else {
document.getElementById(feedbackId).textContent = "❌ Incorrect, continue !";
document.getElementById(feedbackId).style.color = "red";
}
return 0;
}
function nextQuiz(hw, hanzi, fbok, fbpok) {
hw.setCharacter(hanzi);
startQuiz1(hw, fbok, fbpok);
}
// On expose uniquement init()
return {
init
};
} }
</script> // ---------------------------------------------------------
// LANCER UN QUIZ PAR CANVAS
// ---------------------------------------------------------
function startMultiQuiz(writers, okArray) {
writers.forEach((hw, idx) => {
okArray[idx] = false; // reset
hw.quiz({
onMistake: () => { okArray[idx] = false; },
onCorrectStroke: () => {},
onComplete: () => { okArray[idx] = true; }
});
});
}
// ---------------------------------------------------------
// CHECK GLOBAL
// ---------------------------------------------------------
function checkAll(okArray, feedbackId) {
const allOK = okArray.every(v => v === true);
if (allOK) {
document.getElementById(feedbackId).textContent = "✔️ Bravo !";
document.getElementById(feedbackId).style.color = "green";
return 1;
} else {
document.getElementById(feedbackId).textContent = "❌ Incorrect, continue !";
document.getElementById(feedbackId).style.color = "red";
return 0;
}
}
// ---------------------------------------------------------
// EXPORT
// ---------------------------------------------------------
return {
init
};
}
</script>

17
styles.html Normal file
View file

@ -0,0 +1,17 @@
<style>
.hanzi-canvas-container {
display: flex !important;
flex-direction: row !important;
gap: 12px;
align-items: flex-start;
flex-wrap: nowrap !important;
margin-bottom: 10px;
border: 2px solid #000;
padding: 10px;
}
.hanzi-canvas-container > div {
display: inline-flex !important;
flex: 0 0 auto !important;
}
</style>