legacy/outils/tableauconversion/TableauConversion.js

import { j3pAjouteDiv, j3pAjouteZoneTexte, j3pComplete, j3pDiv, j3pElement } from 'src/legacy/core/functions'
import { hasProp } from 'sesajs/object'
import { j3pMathsAjouteDans } from 'src/lib/mathquill/functions'
import { j3pCreeRectangle, j3pCreeSegment, j3pCreeSVG, j3pCreeTexte, j3pCreeVirgule } from 'src/legacy/core/functionsSvg'

/**
 * Outil tableauconversion pour créer un tableau de conversion
 * @name TableauConversion
 * @param {HTMLElement|string} container
 * @param {Object} [values]
 * @constructor
 */
function TableauConversion (container, values) {
  if (!this || typeof this !== 'object') throw Error('Constructeur qui doit être appelé avec new')
  /*
  this.lesclasses = ["milliards","millions","milliers","unites","milliemes","millioniemes"]

  values = {`
      idDIV : string; // id du div contenant le tableau
      classes : [i,j],
      // i < j et 0:"milliards" , 1:"millions" , 2:"milliers" , 3:"unites" , 4:"milliemes" , 5:"millioniemes"
      format : {
                      idDIV:"tableau",
                      classes:[2,4],
                      format :{
                          top : 10,
                          left:10,
                          labelsclasses:true,
                          labelscols:true,
                          hclasse:70,
                          hcol:50,
                          hlig:70,
                          largeurcol:60,
                          police:"times new roman",
                          taillepolice : 20,
                          taillechiffres : 28,
                          taillevirgule : 20,
                          epaisseurs :{
                              separateurclasses : 4,
                              ligneclasse : 4,
                              lignecols : 3,
                              separateurcols : 3,
                              lignehorizontale : 1,
                              cadre : 6
                          },
                          couleurs:{
                              labels:"#000000",
                              cols:"#000000",
                              chiffres:"#000000",
                              virgule:"#000000",
                              separateurclasses:"#00506B",
                              separateurcols:"#009DD1",
                              lignehorizontale:"#009DD1",
                              lignehorizontaleclasse:"#00506B",
                              lignehorizontalecdu:"#00506B",
                              cadre:"#002EB8"
                          }
                      }
      lignes : Array
          lignes[k] : contenu de la ligne k
          lignes[k] = {
                          milliards:[a,b,c],
                          millions:[a,b,c],
                          milliers:[a,b,c],
                          unites:[a,b,c],
                          milliemes:[a,b,c],
                          millioniemes:[a,b,c]

                      }
                      AVEC
                              a = "." ==> FERME
                              a = "?_" ==> ZDT vide
                              a = "?5" ==> ZDT contenant le chiffre 5
                              a = 4 ==> chiffre 4 dans la case

  }

  */
  /**
   * Le conteneur du tableau
   * @memberOf TableauConversion
   * @type {HTMLElement}
   */
  this.container = (typeof container === 'string') ? j3pElement(container) : container
  /**
   * Id du conteneur, peut être undefined
   * @memberOf TableauConversion
   * @deprecated
   * @type {string}
   */
  this.conteneur = this.container.id
  this.idDIV = values.idDIV
  this.lesclasses = ['Milliards', 'Millions', 'Milliers', 'Unités', 'Millièmes', 'Millionièmes']
  // Définition de toutes les propriétés et initialisation si absence dans values
  this.classes = values.classes
  // le format, avec ces valeurs par défaut
  const defaultFormat = {
    relative: false,
    top: 0,
    left: 0,
    labelsclasses: true,
    labelscols: true,
    labelscolsdecimaleslettres: false,
    virgule: [false, false, false, false, false, false, false],
    // nblignes est imposé par la taille de values.lignes
    hclasse: 40,
    hcol: 40,
    hlig: 50,
    largeurcol: 50,
    police: 'verdana',
    taillepolice: 20,
    taillepoliceclasses: 20,
    taillechiffres: 20,
    taillevirgule: 20,
    epaisseurs: {
      separateurclasses: 4,
      separateurcols: 3,
      lignehorizontale: 1,
      cadre: 6,
      ligneclasse: 4,
      lignecols: 3
    },
    couleurs: {
      labels: '#000000',
      cols: '#339966',
      chiffres: '#000000',
      virgule: '#000000',
      separateurclasses: '#00506B',
      separateurcols: '#009DD1',
      lignehorizontaleclasse: '#00506B',
      lignehorizontalecdu: '#00506B',
      lignehorizontale: '#009DD1',
      cadre: '#002EB8'
    }
  }
  this.format = j3pComplete(defaultFormat, values.format)
  // on remet virgule au cas où ce serait autorisé de passer un nb d’élément ≠ de celui par défaut
  if (values.format && Array.isArray(values.format.virgule)) this.format.virgule = values.format.virgule

  this.lignes = values.lignes
  this.format.nblignes = this.lignes.length

  this.hauteurSVG = this.format.nblignes * this.format.hlig
  if (this.format.labelsclasses) this.hauteurSVG += this.format.hclasse
  if (this.format.labelscols) this.hauteurSVG += this.format.hcol
  let nbcol = 0
  this.premiereclasse = 0
  let trouve = false
  for (let k = 0; k < this.lignes[0].length; k++) {
    if (this.lignes[0][k].length !== 0) {
      nbcol++
      if (!trouve) {
        this.premiereclasse = k
        trouve = true
      }
    }
  }
  this.largeurSVG = 3 * nbcol * this.format.largeurcol
  this.nbcol = 3 * nbcol
  this.construit()
}

TableauConversion.prototype.construit = function () {
  /**
   * Retourne this.idDIV + suffix, ou undefined
   * @param {string} suffix
   * @return {string|undefined}
   */
  function getId (suffix) {
    if (idConteneur) return idConteneur + suffix
  }

  const idConteneur = this.idDIV
  const styleTab = {
    position: (this.format.relative ? 'relative' : 'absolute')
  }
  // on ne le précise que si on l’avait fourni (ou que top a été affecté dans le constructeur
  if (hasProp(this.format, 'top')) styleTab.top = this.format.top + 'px'
  if (hasProp(this.format, 'left')) styleTab.left = this.format.left + 'px'
  // si on est positionné en absolu mais que notre parent n’est pas positionné ça déconne
  // visiblement y’a eu une modif qq part qui ne fait plus de positionnement systématique
  // on sait pas très bien où, donc on l’ajoute ici
  if (styleTab.position === 'absolute' && (!this.container.style || !this.container.style.position)) {
    if (!this.container.style) this.container.style = {}
    this.container.style.position = 'relative'
  }
  const divSvg = j3pAjouteDiv(this.container, this.idDIV, '', {
    style: styleTab
  })
  const svg = j3pCreeSVG(divSvg, {
    id: getId('svg'),
    width: this.largeurSVG,
    height: this.hauteurSVG
  })
  j3pCreeRectangle(svg, {
    id: getId('cadre'),
    x: 0,
    y: 0,
    width: this.largeurSVG,
    height: this.hauteurSVG,
    couleur: this.format.couleurs.cadre,
    couleurRemplissage: '',
    epaisseur: this.format.epaisseurs.cadre
  })

  let decal = 0
  if (this.format.labelsclasses) {
    // permier trait horizontal
    decal += this.format.hclasse
    j3pCreeSegment(svg, {
      id: getId('ligneclasses'),
      x1: 0,
      y1: decal,
      x2: this.largeurSVG,
      y2: decal,
      couleur: this.format.couleurs.lignehorizontaleclasse,
      epaisseur: this.format.epaisseurs.ligneclasse
    })
  }
  if (this.format.labelscols) {
    decal += this.format.hcol
    j3pCreeSegment(svg, {
      id: getId('lignecols'),
      x1: 0,
      y1: decal,
      x2: this.largeurSVG,
      y2: decal,
      couleur: this.format.couleurs.lignehorizontalecdu,
      epaisseur: this.format.epaisseurs.lignecols
    })
  }
  let k, u, v, ch, numligne
  for (k = 0; k < this.format.nblignes - 1; k++) {
    j3pCreeSegment(svg, {
      id: getId('lignelig' + k),
      x1: 0,
      y1: decal + (k + 1) * this.format.hlig,
      x2: this.largeurSVG,
      y2: decal + (k + 1) * this.format.hlig,
      couleur: this.format.couleurs.lignehorizontale,
      epaisseur: this.format.epaisseurs.lignehorizontale
    })
  }

  decal = 0
  if (this.format.labelsclasses) decal += this.format.hclasse

  for (k = 0; k < this.nbcol - 1; k++) {
    j3pCreeSegment(svg, {
      id: getId('lignecol' + k),
      x1: (k + 1) * this.format.largeurcol,
      y1: decal,
      x2: (k + 1) * this.format.largeurcol,
      y2: this.hauteurSVG,
      couleur: this.format.couleurs.separateurcols,
      epaisseur: this.format.epaisseurs.separateurcols
    })
  }

  for (k = 0; k < (this.nbcol / 3) - 1; k++) {
    j3pCreeSegment(svg, {
      id: getId('lignecolclasses' + k),
      x1: 3 * (k + 1) * this.format.largeurcol,
      y1: 0,
      x2: 3 * (k + 1) * this.format.largeurcol,
      y2: this.hauteurSVG,
      couleur: this.format.couleurs.separateurclasses,
      epaisseur: this.format.epaisseurs.separateurclasses
    })
  }
  const centragex = (this.format.largeurcol - 12) / 2
  if (this.format.labelscols) {
    const temp = ['c', 'd', 'u']
    for (k = 0; k < this.nbcol; k++) {
      u = k % 3
      decal = 5
      if (this.format.labelsclasses) decal += this.format.hclasse

      if (Math.floor(k / 3) + this.premiereclasse <= 3) {
        // les classes non décimales
        j3pCreeTexte(svg, {
          x: centragex + (k) * this.format.largeurcol,
          y: 30 + this.format.top + decal,
          texte: temp[u],
          taille: (this.format.taillepolice) * (3 / 4),
          couleur: this.format.couleurs.cols,
          fonte: this.format.police,
          italique: true
        })
      } else {
        const nbzeros = 1 + u + (Math.floor(k / 3) + this.premiereclasse - 4) * 3
        let divNbZeros
        if (nbzeros < 4) {
          divNbZeros = j3pDiv(divSvg, getId('decimale' + nbzeros), '', [-10 + centragex + (k) * this.format.largeurcol, this.format.top + decal])
        } else {
          divNbZeros = j3pDiv(divSvg, getId('decimale' + nbzeros), '', [-15 + centragex + (k) * this.format.largeurcol, this.format.top + decal + 5])
        }
        divNbZeros.style.fontFamily = this.format.police

        ch = ''
        for (let j = 0; j < nbzeros; j++) ch += '0'
        if (this.format.labelscolsdecimaleslettres) {
          if (nbzeros < 4) {
            let sch = ''
            switch (nbzeros) {
              case 1:
                sch = 'dixième'
                break
              case 2:
                sch = 'centième'
                break
              case 3:
                sch = 'millième'
                break
            }
            divNbZeros.innerHTML = sch
            const left = divNbZeros.style.left
            const top = divNbZeros.style.top
            divNbZeros.style.left = (Number(left.substring(0, left.length - 2)) - 10) + 'px'
            divNbZeros.style.top = (Number(top.substring(0, top.length - 2)) + 12) + 'px'
          } else {
            j3pMathsAjouteDans(divNbZeros, { content: '$\\frac{1}{1' + ch + '}$' })
          }
        } else {
          j3pMathsAjouteDans(divNbZeros, { content: '$\\frac{1}{1' + ch + '}$' })
        }

        if (nbzeros < 4) {
          if (this.format.labelscolsdecimaleslettres) {
            divNbZeros.style.fontSize = '9pt'
          } else {
            divNbZeros.style.fontSize = '12pt'
          }
        } else {
          divNbZeros.style.fontSize = '9pt'
        }
      }
    }
  }

  if (this.format.labelsclasses) {
    for (k = 0; k < (this.nbcol / 3); k++) {
      const centragex1 = 35
      if (k + this.premiereclasse <= 3) {
        // j3pCreeTexte(svg,{id:"texteclassek",x:centragex1+(3*k)*this.format.largeurcol,y:20+this.format.top,texte:"Classe des",taille:this.format.taillepolice-4,couleur:this.format.couleurs.labels,fonte:this.format.police,italique:true})
        j3pCreeTexte(svg, {
          x: centragex1 + 10 + (3 * k) * this.format.largeurcol,
          y: (3 / 4) * this.format.hclasse + this.format.top,
          texte: this.lesclasses[k + this.premiereclasse],
          taille: (this.format.taillepoliceclasses) * (3 / 4),
          couleur: this.format.couleurs.labels,
          fonte: this.format.police,
          italique: true
        })
      } else {
        j3pCreeTexte(svg, {
          x: 10 + (3 * k) * this.format.largeurcol,
          y: (3 / 4) * this.format.hclasse + this.format.top,
          texte: 'Partie décimale',
          taille: (3 / 4) * (this.format.taillepolice - 4),
          couleur: this.format.couleurs.labels,
          fonte: this.format.police,
          italique: true
        })
      }
    }
  }

  // creation des DIV des différentes cases
  let x, y
  const colDivs = []
  for (numligne = 0; numligne < this.lignes.length; numligne++) {
    colDivs[numligne] = []
    for (k = 0; k < this.nbcol; k++) {
      u = k % 3
      decal = 0
      if (this.format.labelsclasses) decal += this.format.hclasse
      if (this.format.labelscols) decal += this.format.hcol
      decal += this.format.hlig * numligne - 1
      x = centragex + (k) * this.format.largeurcol
      y = this.format.taillechiffres / 2 + this.format.top + decal
      colDivs[numligne][k] = j3pDiv(divSvg, {
        coord: [x, y],
        style: {
          fontFamily: this.format.police,
          fontSize: this.format.taillechiffres + 'px',
          color: this.format.couleurs.chiffres,
          width: '30px'
        }
      })
    }
  }

  let tabindex = 0
  for (numligne = 0; numligne < this.lignes.length; numligne++) {
    for (k = 0; k < this.nbcol; k++) {
      v = k % 3
      u = this.premiereclasse + Math.floor(k / 3)
      ch = this.lignes[numligne][u][v]
      switch (ch) {
        case '?_': {
          const inputElt = j3pAjouteZoneTexte(colDivs[numligne][k],
            {
              id: this.idDIV + 'divcoltexte' + numligne + '_' + k,
              maxchars: '1',
              restrict: /\d/,
              texte: '',
              police: this.format.police,
              width: 30,
              tailletexte: this.format.taillechiffres,
              fond: '#FFF',
              couleur: this.format.couleurs.chiffres,
              taille: 1,
              top: -this.format.taillechiffres / 2 + 6,
              left: -10,
              tabindex: tabindex++
            }
          )
          inputElt.style.textAlign = 'center'
          break
        }
        case '.':
          break
        default:
          colDivs[numligne][k].innerHTML = ch
          break
      }
    }

    decal = 0
    if (this.format.labelsclasses) decal += this.format.hclasse
    let decal2 = 0
    if (this.format.labelscols) decal2 = decal + this.format.hcol

    const emplacement = [3 * (4 - this.premiereclasse) * this.format.largeurcol, decal2 + this.format.hlig * (numligne + 2 / 3)]

    if (this.format.virgule[numligne]) {
      j3pCreeVirgule(svg, {
        id: this.idDIV + 'virgule' + numligne,
        top: emplacement[1],
        left: emplacement[0],
        rayon: 6,
        couleur: '#F00',
        couleurRemplissage: '#F00',
        hauteur: 20,
        angle: 45
      })
    }
  }
}

TableauConversion.creeLigne = function (entier, unite, bool, classes) {
  // classes = [i,j]  i,i entre 0 et 5
  // classes affichées
  // bool = true : si le nombre<1, et si pas de 1/10 par ex, on met un zéro dans les 1/10

  function convertit (nb) {
    // 13==>[4,1]
    // 5==>[1,2]
    const a = Math.floor(nb / 3 + 0.01)
    const b = nb % 3
    return [a, b]
  }

  const res = [[], [], [], [], [], []]
  /* unite : entier entre 0 et 17
  creetableau(3510,13,false) ==> [[],[],[],[.,"3","5"],["1","0",.],[]]
  */

  const tab = String(entier).split('')// ["3","5","1","0"]
  // 0 ==> dans case 13
  // 1 ==> dans case 12
  // 5 ==> dans case 11
  // 3 ==> dans case 10

  let k
  for (k = 0; k < tab.length; k++) {
    // tab[k] dans case unite-(tab.length-1) + k
    const tob = convertit(unite - (tab.length - 1) + k)
    res[tob[0]][tob[1]] = tab[k]
  }

  for (k = 0; k < 6; k++) {
    if (res[k].length !== 0) {
      let u = 0
      while ((typeof (res[k][u]) === 'undefined') && (u < 3)) {
        if ((bool) && (k >= 4)) {
          res[k][u] = '0'
        } else {
          res[k][u] = '.'
        }

        u++
      }
    }
    if ((res[3].length === 0) && (res[4].length !== 0) && bool) {
      res[3][2] = '0'
    }
  }

  for (k = classes[0]; k <= classes[1]; k++) {
    if (res[k].length === 0) {
      res[k] = ['.', '.', '.']
    }
  }

  for (k = 0; k < 6; k++) {
    switch (res[k].length) {
      case 1:
        res[k][1] = '.'
        res[k][2] = '.'
        break
      case 2:

        res[k][2] = '.'
        break
    }
  }

  // il faut compléter
  if ((res[1].length === 0) && (res[0].length !== 0)) {
    res[1] = ['0', '0', '0']
    res[2] = ['0', '0', '0']
    res[3] = ['0', '0', '0']
  }
  if ((res[1].length !== 0) && (res[2].length === 0)) {
    res[2] = ['0', '0', '0']
    res[3] = ['0', '0', '0']
  }
  if ((res[2].length !== 0) && (res[3].length === 0)) {
    res[3] = ['0', '0', '0']
  }
  if ((res[3].length === 0) && (res[4].length !== 0)) {
    res[3] = ['.', '.', '0']
  }
  if ((res[4].length === 0) && (res[5].length !== 0)) {
    res[3] = ['.', '.', '0']
    res[3] = ['0', '0', '0']
  }

  return res
}

export default TableauConversion