import { j3pAddContent, j3pAddElt, j3pAjouteBouton, j3pArrondi, j3pClone, j3pElement, j3pEmpty, j3pGetNewId, j3pGetRandomBool, j3pGetRandomElt, j3pIsHtmlElement, j3pShowError, j3pShuffle } from 'src/legacy/core/functions'
import { j3pCreeSVG } from 'src/legacy/core/functionsSvg'
import { j3pAffiche } from 'src/lib/mathquill/functions'
import { getMtgCore } from 'src/lib/outils/mathgraph'
import MenuContextuel from 'src/legacy/outils/menuContextuel'
import { getJ3pConteneur } from 'src/lib/core/domHelpers'
import ffondd from './ffondd.jpg'
import { modeles } from './datas'
import './zoneColoriage.css'
import { placeJouerSon } from 'src/legacy/outils/zoneStyleMathquill/functions'
/**
* Le background initial d’une case (utilisé pour savoir si on l’a coloriée)
* @type {string}
* @private
*/
// fixme 'tansparant' ca va pas, y’a des dessins en noirs et blanc
const emptyColor = 'url(' + ffondd + ')'
class ZoneColoriage {
/**
*
* @param {Object} values
* @param {HTMLElement|string} values.conteneur le div contenant le pixel
* @param {} values.classes un tableau contenant les modèle, les contenus associés
* @param {} values.dim le cote du carré
*/
constructor ({ conteneur, classes, dim, j3pCont }) {
if (typeof conteneur === 'string') conteneur = j3pElement(conteneur)
if (!j3pIsHtmlElement(conteneur)) throw Error('Conteneur invalide')
conteneur.classList.add('zoneColoriage')
/**
* Le conteneur
* @type {HTMLElement}
*/
this.conteneur = conteneur
this.classes = classes
this.dim = dim
this.j3pCont = j3pCont
this._isMenuOpen = false
/**
* La zone j3p totale (class j3pContainer) dans laquelle se trouve notre conteneur
* @type {HTMLElement}
*/
this.parent = getJ3pConteneur(conteneur, true) || j3pElement('j3pContainer')
if (!this.parent) throw Error('Pas trouvé de conteneur')
if (this.parent.URL) this.parent = j3pElement('j3pContainer')
// trouve un dessin en fonction de dim et du nb de classes
const modelesPossibles = modeles.filter(m => m.t === this.dim && m.couleurs.length === this.classes.length)
if (!modelesPossibles.length) throw Error(`Aucun modèle avec la dimension ${this.dim} et ${this.classes.length} couleurs`)
// on en prend un au hasard dans la liste
this.modeleEnCours = j3pGetRandomElt(modelesPossibles)
if (this.modeleEnCours.changeCoul) {
this.modeleEnCours.couleurs = j3pShuffle(this.modeleEnCours.couleurs)
}
if (this.modeleEnCours.invHautBas && j3pGetRandomBool()) {
const tabuf = []
for (let i = 0; i < this.dim; i++) {
for (let j = 0; j < this.dim; j++) {
tabuf[i + (this.dim - j - 1) * this.dim] = this.modeleEnCours.tab[i + j * this.dim]
}
}
this.modeleEnCours.tab = tabuf
}
if (this.modeleEnCours.InvGaucheDroite && j3pGetRandomBool()) {
const tabuf = []
for (let i = 0; i < this.dim; i++) {
for (let j = 0; j < this.dim; j++) {
tabuf[this.dim - i - 1 + j * this.dim] = this.modeleEnCours.tab[i + j * this.dim]
}
}
this.modeleEnCours.tab = tabuf
}
if (this.modeleEnCours.tourneD && j3pGetRandomBool()) {
const tabuf = []
for (let i = 0; i < this.dim; i++) {
for (let j = 0; j < this.dim; j++) {
tabuf[j + i * this.dim] = this.modeleEnCours.tab[i + j * this.dim]
}
}
this.modeleEnCours.tab = tabuf
}
this.changeCoList = this._changeCorrection.bind(this)
/**
* Passe à true dès que mtg est chargé et tout est affiché
* @type {boolean}
* @private
*/
this._isReady = false
this.oldcarr = undefined
getMtgCore({ withMathJax: true })
.then(
// success
(mtgAppLecteur) => {
this.mtgAppLecteur = mtgAppLecteur
this.mtgAppLecteur.removeAllDoc()
this._initDisplay()
},
// failure
(error) => {
j3pShowError(error, { message: 'mathgraph n’est pas correctement chargé', mustNotify: true })
})
// plantage dans enonceMain
.catch(j3pShowError)
}
/**
* Affiche le tableau (dès que mathgraph est chargé)
* @private
*/
_initDisplay () {
this.plateau = j3pAddElt(this.conteneur, 'div', null, {
style: {
display: 'grid',
gridTemplateColumns: 'auto 20px auto',
gridTemplateRows: 'auto',
rowGap: '10px'
}
})
this.yy = j3pAddElt(this.plateau, 'div', null, {
gridColumn: 1,
gridRow: 1
})
this.menu = j3pAddElt(this.plateau, 'div', null, {
style: {
gridColumn: 3,
gridRow: 1,
display: 'grid',
gridTemplateColumns: '1fr',
gridTemplateRows: 'repeat(' + (this.classes.length + 2) + ', auto)',
rowGap: '1px',
columnGap: '1px'
}
})
const titre = j3pAddElt(this.menu, 'div', null, {
style: {
gridColumn: 1,
gridRow: 1,
display: 'flex',
padding: '10px',
border: '3px solid blue',
borderRadius: '1px',
verticalAlign: 'middle',
justifyContent: 'center',
alignItems: 'center',
background: '#97eed6'
}
})
j3pAddContent(titre, '<b><u>Couleurs disponibles</u></b>')
this.menuChoices = []
this.classes.forEach(el => {
this.menuChoices.push({
name: String(this.classes.indexOf(el)),
label: 'couleur ' + (1 + this.classes.indexOf(el))
})
const MenuCool = j3pAddElt(this.menu, 'div', null, {
style: {
gridColumn: 1,
gridRow: 2 + this.classes.indexOf(el),
display: 'flex',
padding: '10px',
border: '3px solid black',
borderRadius: '1px',
justifyContent: 'left',
alignItems: 'center',
background: '#c1f3db'
}
})
j3pAddElt(MenuCool, 'div', null, {
style: {
borderRadius: '1px',
background: this.modeleEnCours.couleurs[this.classes.indexOf(el)],
width: '40px',
height: '40px'
},
className: 'cases2'
})
const lacoulT = j3pAddElt(MenuCool, 'div', null, {
style: {
paddingLeft: '10px'
}
})
if (typeof el.mod === 'string') {
j3pAffiche(lacoulT, null, el.mod)
} else {
if (el.mod.type === 'mathgraph') {
const svgID = j3pGetNewId('mttm')
const width = (el.mod.width) ? (4 / 3 * el.mod.width - 32) : 130
const height = (el.mod.content.height) ? (8 / 9 * el.mod.content.height + 7) : 90
j3pCreeSVG(lacoulT, { id: svgID, width, height })
this.mtgAppLecteur.addDoc(svgID, el.mod.content.txtFigure, true)
if (el.mod.A) this.mtgAppLecteur.giveFormula2(svgID, 'A', el.mod.A)
if (el.mod.ALEA) this.mtgAppLecteur.giveFormula2(svgID, 'ALEA', el.mod.ALEA)
this.mtgAppLecteur.calculate(svgID, true)
this.mtgAppLecteur.display(svgID)
}
if (el.mod.type === 'image') {
const immm = j3pAddElt(lacoulT, 'img', '', { src: el.mod.content.txtFigure, width: el.mod.content.width, height: el.mod.content.height })
immm.style.width = el.mod.content.width + 'px'
immm.style.height = el.mod.content.height + 'px'
}
if (el.mod.type === 'son') {
const ui = j3pAddElt(lacoulT, 'div')
ui.style.border = '1px solid black'
ui.style.borderRadius = '5px'
ui.style.padding = '5px'
ui.style.paddingTop = '0px'
ui.style.background = '#aeef59'
ui.style.textAlign = 'center'
placeJouerSon(ui, el.mod.content, this, 'txtFigure')
}
}
})
this.fig = j3pAddElt(this.yy, 'div', null, {
style: {
display: 'grid',
gridTemplateColumns: 'repeat(' + this.dim + ', 1fr)',
gridTemplateRows: 'repeat(' + this.dim + ', 1fr)',
rowGap: '1px',
columnGap: '1px',
border: '3px solid black',
borderRadius: '1px'
}
})
this.cases = []
for (let i = 0; i < this.dim; i++) {
this.cases[i] = []
for (let j = 0; j < this.dim; j++) {
this.cases[i][j] = {
carre: j3pAddElt(this.fig, 'div', '', {
style: {
gridColumn: i + 1,
gridRow: j + 1,
background: emptyColor
},
className: 'case',
backgroundSave: emptyColor
})
}
const am = j3pClone(this.menuChoices)
am.forEach(el => {
el.callback = (a, b) => {
this.cases[i][j].carre.style.background = this.modeleEnCours.couleurs[Number(b.name)]
this.cases[i][j].carre.backgroundSave = this.modeleEnCours.couleurs[Number(b.name)]
this.cases[i][j].carre.style.border = ''
}
})
this.cases[i][j].menu = new MenuContextuel(this.cases[i][j].carre, am, {}, {
pasToucheBackground: true,
j3pCont: this.j3pCont,
colle: true,
callBackOpen: this._getCallbackOpen(i, j),
callBackClose: () => { this._isMenuOpen = false }
})
this.cases[i][j].cont = this.classes[this.modeleEnCours.tab[i + j * this.dim]].func()
this.cases[i][j].carre.addEventListener('mouseover', this._getMouseOverListener.bind(this, i, j), false)
for (let k = 0; k < this.classes.length; k++) {
j3pEmpty(this.cases[i][j].menu.listeChoicesMenu[k].elt)
const elcoul = j3pAddElt(this.cases[i][j].menu.listeChoicesMenu[k].elt, 'div')
elcoul.style.border = '1px solid black'
elcoul.style.background = this.modeleEnCours.couleurs[k]
elcoul.backgroundSave = this.modeleEnCours.couleurs[k]
elcoul.style.height = '20px'
elcoul.style.width = '40px'
}
}
}
const uu = j3pAddElt(this.menu, 'div', null, {
style: {
gridColumn: 1,
gridRow: 2 + this.classes.length,
marginTop: '10px',
// display: 'flex',
padding: '10px',
border: '3px solid blue',
borderRadius: '1px',
background: '#fff',
// verticalAlign: 'middle',
justifyContent: 'center'
// alignItems: 'center'
}
})
const ff = j3pAddElt(uu, 'div', null, {
style: {
gridColumn: 1,
gridRow: 2,
textAlign: 'center'
}
})
j3pAddContent(ff, '<u>Contenu de la case selectionnée</u>:<br>')
this.caseCont = j3pAddElt(uu, 'div', null, {
style: {
gridColumn: 1,
gridRow: 2,
textAlign: 'center',
display: 'flex',
verticalAlign: 'middle',
justifyContent: 'center',
alignItems: 'center'
}
})
this._isReady = true
}
/**
* Retourne une callback pour la propriété callBackOpen d’un MenuContextuel
* @param i
* @param j
* @return {(function(): void)} le listener
* @private
*/
_getCallbackOpen (i, j) {
return () => {
setTimeout(() => { this._isMenuOpen = true }, 10)
j3pEmpty(this.caseCont)
if (this.oldcarr) this.cases[this.oldcarr.i][this.oldcarr.j].carre.style.border = ''
this.oldcarr = { i, j }
const current = this.cases[i][j]
current.carre.style.border = '1px solid red'
if (typeof current.cont === 'string') {
j3pAffiche(this.caseCont, null, current.cont)
} else {
if (current.cont.type === 'mathgraph') {
if (this.oldSvg) {
this.mtgAppLecteur.removeDoc(this.oldSvg)
}
const sgvId = j3pGetNewId('mtt')
const w1 = Number(current.cont.content.width) || Number(current.cont.content.modDimx)
let width = (w1) ? (4 / 3 * w1 - 32) : 130
const w2 = Number(current.cont.content.height) || Number(current.cont.content.modDimy)
let height = (w2) ? (8 / 9 * w2 + 7) : 90
if (width < 20) width = 130
if (height < 20) height = 90
j3pCreeSVG(this.caseCont, { id: sgvId, width, height })
this.mtgAppLecteur.addDoc(sgvId, current.cont.content.txtFigure, true)
if (current.cont.content.A) this.mtgAppLecteur.giveFormula2(sgvId, 'A', current.cont.content.A)
if (current.cont.content.ALEA) this.mtgAppLecteur.giveFormula2(sgvId, 'ALEA', current.cont.content.ALEA)
this.mtgAppLecteur.calculateAndDisplayAll(true)
this.oldSvg = sgvId
}
if (current.cont.type === 'image') {
const immm = j3pAddElt(this.caseCont, 'img', '', { src: current.cont.content.txtFigure, width: current.cont.content.width, height: current.cont.content.height })
immm.style.width = current.cont.content.width + 'px'
immm.style.height = current.cont.content.height + 'px'
}
if (current.cont.type === 'son') {
const ui = j3pAddElt(this.caseCont, 'div')
ui.style.border = '1px solid black'
ui.style.borderRadius = '5px'
ui.style.padding = '5px'
ui.style.paddingTop = '0px'
ui.style.background = '#aeef59'
ui.style.textAlign = 'center'
placeJouerSon(ui, current.cont.content, this, 'txtFigure')
}
}
}
}
/**
* @typedef voidFunction
* @returns {void}
*/
/**
* Retourne un listener mouseover pour l’objet carre de la case (i, j)
* @param i
* @param j
* @return {voidFunction}
* @private
*/
_getMouseOverListener (i, j) {
if (this._isMenuOpen) return
j3pEmpty(this.caseCont)
if (!this.disabled) {
if (this.oldcarr) this.cases[this.oldcarr.i][this.oldcarr.j].carre.style.border = ''
this.oldcarr = { i, j }
this.cases[this.oldcarr.i][this.oldcarr.j].carre.style.border = '1px solid red'
}
const current = this.cases[i][j]
if (typeof current.cont === 'string') {
j3pAffiche(this.caseCont, null, current.cont)
} else {
if (current.cont.type === 'mathgraph') {
if (this.oldSvg) {
this.mtgAppLecteur.removeDoc(this.oldSvg)
}
const sgvId = j3pGetNewId('mtt')
const w1 = Number(current.cont.content.width) || Number(current.cont.content.modDimx)
let width = (w1) ? (4 / 3 * w1 - 32) : 130
const w2 = Number(current.cont.content.height) || Number(current.cont.content.modDimy)
let height = (w2) ? (8 / 9 * w2 + 7) : 90
if (width < 20) width = 130
if (height < 20) height = 90
j3pCreeSVG(this.caseCont, { id: sgvId, width, height })
this.mtgAppLecteur.addDoc(sgvId, current.cont.content.txtFigure, true)
if (current.cont.content.A) this.mtgAppLecteur.giveFormula2(sgvId, 'A', current.cont.content.A)
if (current.cont.content.ALEA) this.mtgAppLecteur.giveFormula2(sgvId, 'ALEA', current.cont.content.ALEA)
this.mtgAppLecteur.calculateAndDisplayAll(true)
this.oldSvg = sgvId
}
if (current.cont.type === 'image') {
const immm = j3pAddElt(this.caseCont, 'img', '', { src: current.cont.content.txtFigure, width: current.cont.content.width, height: current.cont.content.height })
immm.style.width = current.cont.content.width + 'px'
immm.style.height = current.cont.content.height + 'px'
}
if (current.cont.type === 'son') {
const ui = j3pAddElt(this.caseCont, 'div')
ui.style.border = '1px solid black'
ui.style.borderRadius = '5px'
ui.style.padding = '5px'
ui.style.margin = '5px'
ui.style.paddingTop = '0px'
ui.style.background = '#aeef59'
ui.style.textAlign = 'center'
placeJouerSon(ui, current.cont.content, this, 'txtFigure')
}
}
if (!this.disabled) {
for (let h = 0; h < this.cases.length; h++) {
for (let y = 0; y < this.cases.length; y++) {
if (y === j && h === i) continue
this.cases[h][y].menu.hide()
}
}
}
}
yareponse () {
// on retourne false si une case a encore sa couleur initiale
return !this.cases.some(row => row.some(cell => cell.carre.backgroundSave === emptyColor))
}
isOk () {
let ok = true
this._nbCasesFausses = 0
for (let i = 0; i < this.dim; i++) {
for (let j = 0; j < this.dim; j++) {
if (this.modeleEnCours.tab[i + j * this.dim] !== this.modeleEnCours.couleurs.indexOf(this.cases[i][j].carre.backgroundSave)) {
ok = false
this._nbCasesFausses++
this.cases[i][j].carre.style.border = '3px solid #ce4e00'
} else {
this.cases[i][j].carre.style.border = '3px solid #00FF00'
}
}
}
return ok
}
corrige (bool) {
if (!this._isReady) {
// c’est pas prêt on se rappellera dans 0.1s
return setTimeout(() => this.corrige(bool), 100)
}
this._isCorrection = false
this.caseOub = []
for (let i = 0; i < this.dim; i++) {
this.caseOub[i] = []
for (let j = 0; j < this.dim; j++) {
this.caseOub[i][j] = { coul: this.cases[i][j].carre.backgroundSave, border: this.cases[i][j].carre.style.border }
}
}
if (bool === false) {
j3pAddElt(this.yy, 'div', null)
this._btnCorrection = j3pAjouteBouton(this.yy, this.changeCoList, { value: 'Voir la correction' })
}
}
_changeCorrection () {
this._isCorrection = !this._isCorrection
this._btnCorrection.value = (this._isCorrection) ? 'Voir ma réponse' : 'Voir la correction'
for (let i = 0; i < this.dim; i++) {
for (let j = 0; j < this.dim; j++) {
if (this._isCorrection) {
this.cases[i][j].carre.style.background = this.modeleEnCours.couleurs[this.modeleEnCours.tab[i + j * this.dim]]
this.cases[i][j].carre.backgroundSave = this.modeleEnCours.couleurs[this.modeleEnCours.tab[i + j * this.dim]]
this.cases[i][j].carre.style.border = '2px solid #00F'
} else {
this.cases[i][j].carre.style.background = this.caseOub[i][j].coul
this.cases[i][j].carre.backgroundSave = this.caseOub[i][j].coul
this.cases[i][j].carre.style.border = this.caseOub[i][j].border
}
}
}
}
disable () {
this.disabled = true
if (!this._isReady) {
// faut pas détruire le menu s’il n’a pas encore été créé… on revient dans 0.1s
return setTimeout(() => this.disable(), 100)
}
for (let i = 0; i < this.dim; i++) {
for (let j = 0; j < this.dim; j++) {
this.cases[i][j].menu.destroy()
}
}
}
getScore () {
return j3pArrondi(1 - (this._nbCasesFausses / (this.dim * this.dim)), 1)
}
}
export default ZoneColoriage