objets/CAffLiePt.js

/*
 * MathGraph32 Javascript : Software for animating online dynamic mathematics figures
 * https://www.mathgraph32.org/
 * @Author Yves Biton (yves.biton@sesamath.net)
 * @License: GNU AGPLv3 https://www.gnu.org/licenses/agpl-3.0.html
 */

// Version 6.0 : ON ajoute un angle d'affichage
import Color from '../types/Color'
import Fonte from '../types/Fonte'
import Pointeur from '../types/Pointeur'
import Rect from '../types/Rect'
import StyleEncadrement from '../types/StyleEncadrement'
import { cens, ConvRadDeg, notify } from '../kernel/kernel'
import CElementGraphique from './CElementGraphique'
import Vect from '../types/Vect'
import CValeurAngle from './CValeurAngle'
import addLatex from 'src/kernel/addLatex.js'
import addQueue from 'src/kernel/addQueue'

export default CAffLiePt

/**
 * Classe ancêtre de tous les éléments affichant quelque chose sur la figure.
 * Version spéciale mtgApp car on doit pouvoir capturer un affichage même non encadré
 * @constructor
 * @extends CElementGraphique
 * @param {CListeObjets} listeProprietaire  La liste propriétaire.
 * @param {CImplementationProto} impProto  null ou la construction propriétaire.
 * @param {boolean} estElementFinal  true si l'objet est un élément final de construction.
 * @param {Color} couleur  La couleur d'éciture de l'éditeur (et du cadre éventuel).
 * @param {number} xNom  L'abscisse d'affichage de l'éditeur
 * @param {number} yNom  L'ordonnée d'affichage de l'éditeur
 * @param {number} decX  Décalage horizontal du nom
 * @param {number} decY  Décalage vertical du nom
 * @param {boolean} masque  true si l'éditeur est masqué
 * @param {CPt} pointLie  null ou pointe sur un point auquel l'affichage est lié.
 * @param {number} taillePolice  Indice de la taiile de police utilisée
 * @param {boolean} encadrement  true si encadré.
 * @param {boolean} effacementFond  true si on efface le fond de l'en-tête.
 * @param {Color} couleurFond  La couleur de fond de l'en-tête.
 * @param {number} alignementHorizontal  0 pour alignement gauche, 1 pour centre, 2 pour droite.
 * @param {number} alignementVertical  0 pour alignement vers le haut, 1 pour centré, 2 pour bas.
 * @param {CValeurAngle} angText  L'angle du texte par rapport à l'horizontale dans l'unité d'angle active
 * @param {boolean} fixed true si l'affichage est punaisé et ne peut pas être capturé à la souris
 * @returns {CAffLiePt}
 */
function CAffLiePt (listeProprietaire, impProto, estElementFinal, couleur,
  xNom, yNom, decX, decY, masque, pointLie, taillePolice, encadrement, effacementFond,
  couleurFond, alignementHorizontal, alignementVertical, angText, fixed) {
  if (arguments.length !== 0) {
    if (arguments.length === 1) {
      CElementGraphique.call(this, listeProprietaire)
    } else {
      // A revoir car les deux derniers éléments qui sont enregistrés dans le flux sont inutiles
      CElementGraphique.call(this, listeProprietaire, impProto, estElementFinal, couleur, false,
        decX, decY, masque, '', 0)
      this.xNom = xNom
      this.yNom = yNom
      this.pointLie = pointLie
      this.taillePolice = taillePolice
      this.encadrement = encadrement
      this.effacementFond = effacementFond
      this.couleurFond = couleurFond
      this.alignementHorizontal = alignementHorizontal
      this.alignementVertical = alignementVertical
      if (angText) this.angText = angText; else { this.angText = new CValeurAngle(listeProprietaire, 0) }
      this.fixed = fixed
    }
  }
  // Pour les LaTeX utilisés dans un CEditeurFormule, pointera sur le CEditeurFormule propriétaire
  this.owner = null
  /**
   * Le rectangle qui englobe le point (pour le manipuler)
   * @type {Rect}
   */
  this.rectAff = new Rect(0, 0, 0, 0)
  this.chaineLatex = ''
  // this.div = null // Inutile depuis version MathJax3
}
CAffLiePt.prototype = new CElementGraphique()
CAffLiePt.prototype.constructor = CAffLiePt
CAffLiePt.prototype.superClass = 'CElementGraphique'
CAffLiePt.prototype.className = 'CAffLiePt'

CAffLiePt.alignHorLeft = 0
CAffLiePt.alignHorCent = 1
CAffLiePt.alignHorRight = 2
CAffLiePt.alignVerTop = 0
CAffLiePt.alignVerCent = 1
CAffLiePt.alignVerLow = 2

/**
 * Supprimé version 6.4. Ne sert plus avec MathJax 3.
CAffLiePt.prototype.getStyleLatex = function() {
  return "top:0px;left:0px;position:absolute;font-family: \"Times New Roman\", Times, serif;font-size:" + Fonte.tailleLatex(this.taillePolice)
    +"px;visibility:hidden;"
}
 */

/** @inheritDoc */
CAffLiePt.prototype.setClone = function (ptel) {
  CElementGraphique.prototype.setClone.call(this, ptel)
  this.chaineAAfficher = ptel.chaineAAfficher
  this.taillePolice = ptel.taillePolice
  this.encadrement = ptel.encadrement
  this.effacementFond = ptel.effacementFond
  this.couleurFond = ptel.couleurFond
  this.angText.valeur = ptel.angText.valeur // Ajout version 6.0
  this.fixed = ptel.fixed
  // Ajout version 6.4.0 pour les lieux d'objets de CCommentaire commençant et finissant par un $
  this.chaineLatex = ptel.chaineLatex
  // this.rectAff.setRec(ptel.rectAff); // Ne pas mettre
}

/**
 * Fonction translatant le point de (decalagex, decalagey)
 * @param {number} decalagex
 * @param {number} decalagey
 * @returns {void}
 */
CAffLiePt.prototype.translateDe = function (decalagex, decalagey) {
  this.xNom += decalagex
  this.yNom += decalagey
}

/**
 * Ajout version 5.2 (numéro de version 16). Renverra true si l'objet possède deux éléments decX et decY doit être enregistré dans le flux
 * Sera redéfini à true dans CAffLiePt
 * @returns {boolean}
 */
CAffLiePt.prototype.hasDec = function () {
  return true
}

CAffLiePt.prototype.ajouteAntecedents = function (liste) {
  if (this.pointLie !== null) liste.add(this.pointLie)
}

CAffLiePt.prototype.depDe = function (p) {
  const dep = CElementGraphique.prototype.depDe.call(this, p) || this.angText.depDe(p)
  if (this.pointLie === null) { return dep } else { return dep || this.pointLie.depDe(p) }
}

CAffLiePt.prototype.dependDePourBoucle = function (p) {
  const dep = (p === this) || this.angText.dependDePourBoucle(p)
  if (this.pointLie === null) return dep
  else return dep || this.pointLie.dependDePourBoucle(p)
}

CAffLiePt.prototype.dependDePourCapture = function (p) {
  return this.depDe(p)
}

/**
 * Cette fonction est appelée par CImage car positionne fait des choses pas nécessaires pour ce type d'objet
 * @param infoRandom
 * @param dimf
 */
CAffLiePt.prototype.positionnePourIm = function (infoRandom, dimf) {
  this.angText.positionne()
  this.existe = this.angText.existe
  // Modification version 7.3.3 : Un affichage n'existe pas si le point auquel il est lié
  // est "hors écran"
  // if (this.pointLie !== null) this.existe = this.existe && this.pointLie.existe
  const pointLie = this.pointLie
  if (pointLie !== null) this.existe = this.existe && pointLie.existe && !pointLie.horsEcran
  if (!this.existe) return
  if (pointLie !== null) {
    /* Modifié version mtgApp à cause des lieux d'objets
    if (this.pointLie.horsEcran) {
      this.existe = false;
      return;
    }
    */
    this.xNom = pointLie.x //
    this.yNom = pointLie.y //
    // Les 3 lignes suivantes supprimées version 6.5.2. Posait problème pour j3p et inutile.
    // De toute façon si un affichage de texte , LaTeX ou image est hors fenêtre son composant graphique
    // SVG doit être considéré comme existant
    /*
    if (!dimf.dansFenetre(this.xNom, this.yNom)) {
      this.existe = false
    }
    */
  }
}

// Modifié version 6.4.1 : N'est plus appelé par CLatex.positionne
CAffLiePt.prototype.positionne = function (infoRandom, dimf) {
  this.positionnePourIm(infoRandom, dimf)
  this.chaineAAfficher = this.rendChaineAffichage()
  const len = this.chaineAAfficher.length
  this.isLatex = /^\$.*\$$/.test(this.chaineAAfficher)
  if (this.isLatex) {
    const ch = this.chaineAAfficher.substring(1, len - 1)
    // Ligne suivante modifié version 6.8.1 pour un meilleur fonctionnement des macros d'apparition d'objets
    // Si c'est un affichage LaTeX qui était masqué et qu'une macro d'apparition a mis son membre
    // masqué à false, il faut que l'affichage soit créé
    // this.isToBeUpdated = (this.chaineLatex !== ch)
    this.isToBeUpdated = (this.chaineLatex !== ch) || !this.hasgElement
    this.chaineLatex = ch
  }
}
/**
 * Ajout version 6.4.1 : Nécessaire pour le cas où une macro d'animation a pour éléments à afficher des affichages LaTeX dynamiques
 * @param {boolean} infoRandom
 * @param {Dimf} dimf
 * @returns {void}
 */
CAffLiePt.prototype.positionneFull = function (infoRandom, dimf) {
  this.positionne(infoRandom, dimf)
  if (this.existe) {
    this.chaineAAfficher = this.rendChaineAffichage()
    const len = this.chaineAAfficher.length
    this.isLatex = /^\$.*\$$/.test(this.chaineAAfficher)
    if (this.isLatex) {
      const ch = this.chaineAAfficher.substring(1, len - 1)
      this.isToBeUpdated = true // A cause du fonctionnement asynchrone
      this.chaineLatex = ch
    }
  }
}

// Plus utilisé version 6.4 avec MathJax3
/**
 * Fonction appelée soit ppour un CLaTeX soit pour un commentaire dont le texte commence et finit pat $
 * et qui détruit this.div quand il est non nul qui est la div provisoirement créé pour être traité parr MathJax
 */
/*
CAffLiePt.prototype.deleteDiv = function() {
  if (this.div !== null) {
    document.body.removeChild(this.div);
    this.div = null;
  }
}
*/

CAffLiePt.prototype.distancePoint = function (xp, yp, masquage) {
  if (!this.existe || (masquage && this.masque)) return -1
  else {
    const rectAff = this.rectAff
    const ang = this.angText.rendValeurRadian()
    if (ang === 0) {
      if (rectAff.contains(xp - this.xNom - this.decX, yp - this.yNom - this.decY)) return 0
      else return -1
    } else {
      const x = xp - this.xNom - this.decX
      const y = yp - this.yNom - this.decY
      const v = new Vect(0, 0, x, y)
      const w = new Vect()
      v.tourne(-ang, w)
      const x1 = w.x
      const y1 = w.y
      if (rectAff.contains(x1, y1)) return 0
      else return -1
    }
  }
}

CAffLiePt.prototype.remplacePoint = function (ancienPoint, nouveauPoint) {
  if (this.pointLie === ancienPoint) this.pointLie = nouveauPoint
}

/**
 * Prépare l'affichage par MathJax en créant un div provisoire
 * @param {boolean} [bMemeMasque=false] passer true pour le faire même si l'affichage est masqué (sert dans la boîte de dialogue de protocole)
 * @returns {void}
 */
CAffLiePt.prototype.setReady4MathJax = function setReady4MathJax (bMemeMasque) {
  if (this.isLatex) throw TypeError('Il fallait appeler addLatex avant')
}

CAffLiePt.prototype.setReady4MathJaxUpdate = function setReady4MathJaxUpdate () {
  if (this.isLatex) throw TypeError('Il fallait appeler addLatex avant')
}

/**
 * Ajout version 6.0
 * Positionne l'angle du g element
 */
/*
CAffLiePt.prototype.positionneAngText = function(g) {
  // Ajout version Version 6.0 //////////////////////////////////////////
  var ang = -this.angText.rendValeurRadian();
  var ra = this.rectAff;
  var x = ra.x + ra.width/2;
  var y = ra.y + ra.height/2;
  if (ang !== 0) {
    var angs = String(ang*ConvRadDeg);
    var u = new Vect(0, 0, this.xNom + this.decX, this.yNom + this.decY);
    var v = new Vect();
    u.tourne(ang, v);
    var x1 = String(-x + v.x);
    var y1 = String(-y + v.y);

    g.setAttribute("transform", "translate(" + String(x) + "," + String(y) + ") rotate(" + angs + ") translate(" + x1 + "," + y1 + ")");
  }
  else g.setAttribute("transform", "translate(" + String(this.xNom + this.decX) + "," + String(this.yNom + this.decY) + ")");
  /////////////////////////////////////////////////////////////////////////

}
*/
CAffLiePt.prototype.positionneAngText = function (g) {
  // Ajout version Version 6.0 //////////////////////////////////////////
  const ang = -this.angText.rendValeurRadian()
  const x = this.xNom + this.decX
  const y = this.yNom + this.decY
  if (ang !== 0) {
    const angs = String(ang * ConvRadDeg)
    const u = new Vect(0, 0, x, y)
    const v = new Vect()
    u.tourne(ang, v)
    const x1 = String(v.x)
    const y1 = String(v.y)
    g.setAttribute('transform', 'rotate(' + angs + ') translate(' + x1 + ',' + y1 + ')')
  } else g.setAttribute('transform', 'translate(' + String(this.xNom + this.decX) + ',' + String(this.yNom + this.decY) + ')')
}

CAffLiePt.prototype.createg = function () {
  let t, ch, h, anchor, y, ligaf, ch2, v
  const len = this.chaineAAfficher.length
  // Ajout version mtgApp
  if (len === 0) return cens('g')
  if (this.isLatex) return this.cLatexCreateg()

  this.chaineAffichee = this.chaineAAfficher
  // haut = Fonte.taille(this.taillePolice); Modifié version 5.0
  const haut = this.taillePolice
  const g = cens('g')
  // L'élément va être d'abord caché. S'il est encadré ou efface le fond on rajoutera un élément en tête
  switch (this.alignementHorizontal) {
    case CAffLiePt.alignHorLeft :
      anchor = 'start'
      break
    case CAffLiePt.alignHorCent :
      anchor = 'middle'
      break
    case CAffLiePt.alignHorRight :
      anchor = 'End'
  }
  // On compte le nombre de lignes
  let nblig = 1
  let ind = -1
  while ((ind = this.chaineAAfficher.indexOf('\n', ind + 1)) !== -1) nblig++
  h = (nblig === 1) ? haut : haut + (nblig - 1) * (haut + 2)
  // y = this.decY; // Corrigé version 6.0.1
  y = 0
  if (this.chaineAAfficher.search(/#H|#L/) !== -1) {
    v = haut / 3
    h += v
    y += v
  }
  switch (this.alignementVertical) {
    case CAffLiePt.alignVerCent :
      y -= h / 2 + 1
      break
    case CAffLiePt.alignVerLow :
      y -= h + 2
  }
  // Modifié version 4.9.2.3
  // ligaf = y + haut - 1;
  ligaf = y + haut - 2
  // this.rectAff.height = h;
  // Modifié version 4.9.9.4
  // style = "text-anchor:" + anchor + ";font-size:" + haut +"px;" + "fill:" + this.couleur.rgb()+";";
  // Modifié version 5.1.4 : IL faut préciser une fonte pour les textes
  const sty = "font-family:'Times New Roman',Times,serif;text-anchor:" + anchor + ';fill:' + this.color + ';'
  const style = sty + 'font-size:' + haut + 'px;'
  // Ajout version 5.0
  const styleexp = sty + ';font-size:' + String(Math.round(haut * 2 / 3)) + 'px;'
  // Modification version 5.0 : Une variable globale mémorisant le style d'écriture : italique, gras, souligne ou une combinaison de ces styles
  const st = new Pointeur(Fonte.Normal)
  if (this.chaineAAfficher.indexOf('\n') === -1) {
    t = CAffLiePt.createLine(this.chaineAAfficher, haut, style, styleexp, ligaf, st)
    g.appendChild(t)
  } else {
    ch = this.chaineAAfficher
    // h = haut;
    while ((ind = ch.indexOf('\n')) !== -1) {
      ch2 = ch.substring(0, ind)
      t = CAffLiePt.createLine(ch2, haut, style, styleexp, ligaf, st)
      g.appendChild(t)
      // Modification version 5.0 pour traiter exposants et indices
      ligaf += haut + ((ch2.search(/#H|#L/) !== -1) ? haut / 3 + 2 : 2)
      ch = ch.substring(ind + 1)
    }
    t = CAffLiePt.createLine(ch, haut, style, styleexp, ligaf, st)
    g.appendChild(t)
  }

  g.setAttribute('visibility', 'hidden')
  const svgAux = document.getElementById('mtgSvgAux')
  svgAux.appendChild(g)
  const box = g.getBBox()
  this.rectAff.x = box.x
  this.rectAff.y = y
  /*
    ////////////////////////////////////////////////////////////////////////////
    // Ajout version 6.0 : Quand l'affichage doit être translaté et n'a pas à //
    // être réaffiché; il faut connaître la position relative entre le        //
    // rectangle d'affichage et (xNom, y_no);
    */
  // this.posRel = {x: this.rectAff.x - this.xNom, y : this.rectAff.y - this.yNom};
  /// /////////////////////////////////////////////////////////////////////////
  if (this.effacementFond || (this.encadrement !== StyleEncadrement.Sans)) {
    this.rectAff.width = box.width + 4
    this.rectAff.height = h + 6
    this.creeRectangle(g)
  } else {
    this.rectAff.width = box.width
    this.rectAff.height = h
  }
  svgAux.removeChild(g)
  g.setAttribute('visibility', 'visible')
  // Ligne suivante modifiée version 6.5.2
  g.setAttribute('pointer-events', this.pointerevents)
  // Ajout version Version 6.0
  this.positionneAngText(g)

  /// //////////////////////////////////////////////////////////////////////
  return g
} // createg

CAffLiePt.prototype.cLatexCreateg = function () {
  if (this.isLatex) throw TypeError('Il fallait appeler addLatex avant')
}

/**
 * Fonction créant une ligne de texte dans le cas d'un affichage de plusieurs lignes.
 * Renvoie un élément du type text de svg.
 * @param {string} ch  Le texte de la ligne.
 * @param {number} taille La taille de la police utilisée
 * @param {string} style  le style d'affichage.
 * @param {string} styleexp
 * @param {number} y  L'ordonnée de début d'affichage.
 * @param {Pointeur} st  Contient le style d'écriture actif (combinaison entre normal, italique, gras et souligné)
 * @returns {SVGTextElement}
 */
CAffLiePt.createLine = function createLine (ch, taille, style, styleexp, y, st) {
  let cont, i, tspan, car, ind, diese, affspecial, dy, indpf
  let styleEc = st.getValue()
  const t = cens('text', {
    x: 0,
    y,
    style
  })
  const s = ch.split(/(#)/) // Parenthèses pour que le # soient dans le tableau
  affspecial = false
  diese = false
  dy = 0
  for (i = 0; i < s.length; i++) {
    if (s[i] === '#') {
      if (!diese) {
        affspecial = true
        diese = true
      } else {
        tspan = cens('tspan', {
          style: style + Fonte.styleEcriture(styleEc)
        })
        cont = document.createTextNode('#')
        tspan.appendChild(cont)
        t.appendChild(tspan)
        diese = false
      }
    } else {
      if (s[i].length !== 0) {
        diese = false
        car = s[i].charAt(0)
        ind = 1
        if (affspecial) {
          if ((car === 'I') || (car === 'N') || (car === 'G') || (car === 'U')) {
            if (car === 'I') {
              styleEc |= Fonte.Italique
              ind = 1
            } else if (car === 'N') {
              styleEc = Fonte.Normal
              ind = 1
            } else if (car === 'G') {
              styleEc |= Fonte.Gras
              ind = 1
            } else if (car === 'U') {
              styleEc |= Fonte.Underline
              ind = 1
            }
            if (ind !== s[i].length) {
              tspan = cens('tspan', {
                style: style + Fonte.styleEcriture(styleEc),
                dy: dy + 'px'

              })
              cont = document.createTextNode(s[i].substring(ind))
              tspan.appendChild(cont)
              t.appendChild(tspan)
              affspecial = false
              dy = 0
              // if (dy != 0) dy = -dy; // Un seul niveau d'exposant ou d'indice
            }
          } else {
            if (affspecial && ((car === 'H') || (car === 'L'))) {
              if (s[i].charAt(1) !== '(') {
                ind = 0
                indpf = s[i].length
              } else {
                ind = 2
                indpf = s[i].indexOf(')')
                if (indpf === -1) indpf = s[i].length
                if (car === 'H') dy = -taille / 3
                else dy = taille / 3
              }
              tspan = cens('tspan', {
                style: styleexp + Fonte.styleEcriture(styleEc),
                dy: dy + 'px'
              })

              cont = document.createTextNode(s[i].substring(ind, indpf))
              tspan.appendChild(cont)
              t.appendChild(tspan)
              affspecial = false
              dy = -dy // Un seul niveau d'exposant ou d'indice
              if (indpf < s[i].length - 1) { // Si il reste de caractères après la parenthèse fermante, affichage normal
                tspan = cens('tspan', {
                  style: style + Fonte.styleEcriture(styleEc),
                  dy: dy + 'px'
                })
                cont = document.createTextNode(s[i].substring(indpf + 1))
                tspan.appendChild(cont)
                t.appendChild(tspan)
                affspecial = false
                dy = 0
              }
            } else {
              tspan = cens('tspan', {
                style: style + Fonte.styleEcriture(styleEc),
                dy: dy + 'px'
              })
              cont = document.createTextNode(s[i])
              tspan.appendChild(cont)
              t.appendChild(tspan)
              affspecial = false
              dy = 0
            }
          }
        } else {
          tspan = cens('tspan', {
            style: style + Fonte.styleEcriture(styleEc),
            dy: dy + 'px'
          })
          cont = document.createTextNode(s[i])
          tspan.appendChild(cont)
          t.appendChild(tspan)
          affspecial = false
          dy = 0
        }
      } else affspecial = false
    }
  }
  st.setValue(styleEc)
  t.setAttribute('pointer-events', 'none')
  return t
}

CAffLiePt.prototype.trace = function (svg) {
  // Attention : paramètre svg nécessaire
  const g = this.createg(svg)
  g.setAttribute('id', this.id)
  // g.setAttribute("visibility", "hidden");
  svg.appendChild(g)
  this.g = g
}
/**
 * Dans le cas où l'affichage est encadré, crée un rect de svg qui sera inéséré
 * dans le g element représentant l'objet juste avant l'affichage.
 * @param {SVGRectElement} g
 * @returns {void}
 */
CAffLiePt.prototype.creeRectangle = function (g) {
  // var style = "shape-rendering:crispEdges;stroke-width:1px;";
  let style = 'stroke-width:0.5px;'
  // Modifié version 4.9.9.4
  // style += (this.encadrement === StyleEncadrement.Sans) ? "stroke:none;" : "stroke:" + this.couleur.rgb()+";";
  style += (this.encadrement === StyleEncadrement.Sans) ? 'stroke:none;' : 'stroke:' + this.color + ';'
  if (this.effacementFond) style += 'fill:' + this.couleurFond.rgb() + ';' + 'fill-opacity:' + this.couleur.opacity + ';'
  else style += 'fill:none;'
  const r = cens('rect', {
    style,
    x: this.rectAff.x - 2,
    y: this.rectAff.y - 2,
    width: this.rectAff.width + 3,
    height: this.rectAff.height,
    'pointer-events': 'none'
  })
  g.insertBefore(r, g.childNodes[0])
  if (this.encadrement === StyleEncadrement.Effet3D) { // Ajout d'un effet 3D
    // var pol = document.createElementNS(svgns,"polygon"); // Modifié version mtgApp
    style = 'stroke-width:1px;stroke:' + this.color + ';fill:' + this.color + ';'
    /* Modifié version mtgApp
    pol.setAttribute("style", style);
    */
    const x = this.rectAff.x - 2
    const y = this.rectAff.y - 2
    const w = this.rectAff.width + 3 // Modifié version 4.9.9.4
    const h = this.rectAff.height
    const s1 = String(x + w)
    const s2 = String(y + h)
    const s3 = String(x + w + 1)
    const s4 = String(y + h + 1)
    const pol = cens('polygon', {
      style,
      points: x + ',' + s2 + ' ' + s1 + ',' +
      s2 + ' ' + s1 + ',' + y + ' ' + s3 + ',' + String(y + 1) + ' ' +
      s3 + ',' + s4 + ' ' + String(x + 1) + ',' + s4
    })
    g.insertBefore(pol, g.childNodes[1])
  }
}
/**
 * Fonction retirant de g le rectangle encadrant l'affichage lorsque celui-ci est présent
 * et le remplaçant par un nouveau.
 * @param {SVGElement} g
 * @returns {void}
 */
CAffLiePt.prototype.remplaceRectangle = function (g) {
  g.removeChild(g.childNodes[0])
  if (this.encadrement === StyleEncadrement.Effet3D) g.removeChild(g.childNodes[0])
  this.creeRectangle(g)
}

// Modifié version 5.0 : taille représente maintenant la taille réelle
CAffLiePt.prototype.update = function update (svg) {
  let g
  if (this.isLatex) {
    this.cLatexUpdate(svg)
  } else {
    /*
    decalagex = this.xNom - this.oldxNom + this.decX- this.olddec_x;
    decalagey = this.yNom - this.oldyNom + this.decY - this.olddec_y;
    this.olddec_x = this.decX;
    this.olddec_y = this.decY;
    this.oldxNom = this.xNom;
    this.oldyNom = this.yNom;
    */
    const oldg = this.g
    // if (this.chaineAffichage === this.chaineAffichee) {
    if (this.chaineAAfficher === this.chaineAffichee) {
      // Inutile de recréer le composant on le translate simplement
      /// ///////////////////////////////////////////////////////////////////////
      // Ajout version 6.0 /////////////////////////////////////////////////////
      this.positionneAngText(oldg)
      /// ///////////////////////////////////////////////////////////////////////
      if (this.effacementFond || (this.encadrement !== StyleEncadrement.Sans)) {
        this.remplaceRectangle(oldg)
      }
    } else {
      g = this.createg(svg) // Paramètre nécessaire pour le CLatex
      svg.replaceChild(g, oldg)
      g.setAttribute('id', this.id)
      this.g = g
      if (this.cbmap) this.resetEventListeners() // Ajout version 6.5.2
    }
  }
  // Ajout version 5.0.1
  const visibility = (this.pointLie !== null && !this.pointLie.dansFenetre) ? 'hidden' : 'visible'
  this.g.setAttribute('visibility', visibility)
}
// cette méthode sera remplacée par CLatex.prototype.update
CAffLiePt.prototype.cLatexUpdate = function cLatexUpdateDummy () {
  if (this.isLatex) throw TypeError('Il fallait appeler addLatex avant')
}

CAffLiePt.prototype.reCreateDisplay = function (svg) {
  const oldg = this.g
  const g = this.createg(svg) // Paramètre nécessaire pour le CLatex
  svg.replaceChild(g, oldg)
  g.setAttribute('id', this.id)
  this.g = g
}

// Spécial JavaScript
/**
 * Fonction renvoyant le code à rajouter au début du code LaTeX pour qu'un affichage LaTeX
 * ait la couleur désirée.
 * @returns {string}
 */
CAffLiePt.prototype.prelatex = function () {
  // Modifié version 4.9.9.4
  /*
  return "\\color[RGB]{"+Math.floor(this.couleur.red) +"," + Math.floor(this.couleur.green) + "," +
    Math.floor(this.couleur.blue) + "}";
  */
  return '\\color{' + this.color + '}'
}

CAffLiePt.prototype.read = function (inps, list) {
  CElementGraphique.prototype.read.call(this, inps, list)
  const ind1 = inps.readInt()
  if (ind1 === -1) this.pointLie = null
  else this.pointLie = list.get(ind1, 'CPt')
  this.taillePolice = inps.readByte()
  const numeroVersion = list.numeroVersion
  // Modification version 5.0 : taillePolice est maintenant la taille réelle de la police
  if (numeroVersion < 15) this.taillePolice = Fonte.taille(this.taillePolice)
  if ((numeroVersion < 11)) {
    this.xNom = inps.readDouble()
    this.yNom = inps.readDouble()
  } else {
    if (this.pointLie === null) {
      this.xNom = inps.readDouble()
      this.yNom = inps.readDouble()
    }
  }
  this.encadrement = inps.readByte()
  this.effacementFond = inps.readBoolean()
  // Modification pour le passage en version RVB à partir de la version 2.5 (n°5)
  if (this.effacementFond) {
    const r = inps.readByte()
    const g = inps.readByte()
    const b = inps.readByte()
    this.couleurFond = new Color(r, g, b)
  } else this.couleurFond = Color.white // Ne sert pas
  const tv = this.listeProprietaire.numeroVersion >= 9
  this.alignementHorizontal = tv ? inps.readInt() : CAffLiePt.alignHorLeft
  this.alignementVertical = tv ? inps.readInt() : CAffLiePt.alignVerTop
  this.chaineLatex = '' // Ajout version 4.9.2
  if (numeroVersion >= 18) {
    this.angText = new CValeurAngle()
    this.angText.read(inps, list)
  } else {
    // Ajout version 6.0
    this.angText = new CValeurAngle(list, 0)
  }
  // Depuis le n° de version 21 (version 8.1) les affichages peuvent être punaisés
  if (numeroVersion < 21) {
    this.fixed = false
  } else {
    this.fixed = inps.readBoolean()
  }
}

CAffLiePt.prototype.write = function (oups, list) {
  CElementGraphique.prototype.write.call(this, oups, list)
  let ind1
  if (this.pointLie === null) ind1 = -1
  else ind1 = list.indexOf(this.pointLie)
  oups.writeInt(ind1)
  oups.writeByte(this.taillePolice)
  if (this.pointLie === null) {
    oups.writeDouble(this.xNom)
    oups.writeDouble(this.yNom)
  }
  oups.writeByte(this.encadrement)
  oups.writeBoolean(this.effacementFond)
  if (this.effacementFond) {
    oups.writeByte(this.couleurFond.getRed())
    oups.writeByte(this.couleurFond.getGreen())
    oups.writeByte(this.couleurFond.getBlue())
  }
  oups.writeInt(this.alignementHorizontal)
  oups.writeInt(this.alignementVertical)
  this.angText.write(oups, list) // Ajout version 6.0
  oups.writeBoolean(this.fixed)
}

/**
 * Lance un rendu mathjax
 * @returns {Promise<undefined>} qui sera résolue lorsque le html du rendu mathjax aura été mis dans le dom (ou l'erreur affichée en console)
 */
CAffLiePt.prototype.typeset = function typeset () {
  // la fct à lancer quand on est sûr que MathJax est chargé (fct fléchée pour avoir le bon this)
  const realTypeset = () => {
    const svg = document.getElementById(this.listeProprietaire.id)
    const width = svg.getAttribute('width')
    // var taille = Fonte.tailleLatex(this.taillePolice);
    const taille = this.taillePolice
    // this.ex = taille/2;
    this.ex = taille * 0.45
    const options = { em: taille, ex: this.ex, containerWidth: width, display: false }
    // Pour préserver l'apparence des figures précédentes, quand le code LaTeX contient un seul quotient on passe
    // en mode \displaystyle
    let ch = this.chaineLatex
    const index = ch.indexOf('\\frac{')
    if ((index !== -1) && (index === ch.lastIndexOf('\\frac{'))) ch = '\\displaystyle ' + ch
    return MathJax.tex2svgPromise(this.prelatex() + ch, options)
      .then((html) => {
        this.html = html
      }) // catch inutile car on est dans un addQueue qui le gère
  }

  // faut tester addLatex pour le cas lecteur, au cas où on aurait oublié un useLatex = true sur un des objets,
  // (et donc le chargement du doc a pas fait le addLatex)
  // ou bien si on a appellé setReady4MathJax avant addLatex
  // MAIS ne faut pas de double addQueue ici, car d'autres peuvent faire du addQueue juste après nous,
  // ils auraient donc du code exécuté avant ce realTypeset.
  // Et c'est important de faire le test dans un addQueue, car addLatex peut être déjà lancé mais pas fini
  return addQueue(() => {
    if (typeof MathJax !== 'object' || typeof MathJax.tex2svgPromise !== 'function') {
      // si on a un bugsnag chargé on le signale pour tracer ce cas de figure et le régler en amont
      notify('CAffLiePt.typeset appelé avant addLatex (le pb est rattrapé mais ce serait mieux de le fixer à la source)')
      addLatex.then(realTypeset)
    } else {
      realTypeset()
    }
  })
}

// Fonction ajoutée version 6.5.2 pour permettre de modifier directement des éléments de la figure
/**
 * Fonction donnant directement au svg element représentant l'élément graphique la couleur de l'élément
 */
CAffLiePt.prototype.setgColor = function () {
  return false // pas possible de modifier la couleur d'un affichage de texte ou LaTeX directement
}

// ******* Méthodes qui utilisent CLatex (mis en propriété statique) *********
/**
 * Appelle CLatex.createg() avec l'objet courant
 * @returns {SVGElement}
 */
CAffLiePt.prototype.cLatexCreateg = function () {
  return CAffLiePt.CLatex.prototype.createg.call(this)
}
CAffLiePt.prototype.cLatexUpdate = function (svg) {
  CAffLiePt.CLatex.prototype.update.call(this, svg)
}
/**
 * Prépare l'affichage par MathJax en créant un div provisoire
 * @param {boolean} [bMemeMasque=false] passer true pour le faire même si l'affichage est masqué (sert dans la boîte de dialogue de protocole)
 * @returns {void}
 */
CAffLiePt.prototype.setReady4MathJax = function setReady4MathJax (bMemeMasque) {
  if (this.isLatex) CAffLiePt.CLatex.prototype.setReady4MathJax.call(this, bMemeMasque)
}
/**
 * @returns {void}
 */
CAffLiePt.prototype.setReady4MathJaxUpdate = function () {
  if (this.isLatex) CAffLiePt.CLatex.prototype.setReady4MathJaxUpdate.call(this)
}

CAffLiePt.setLatex = (CLatex) => {
  CAffLiePt.CLatex = CLatex
}