objets/CMacroAnimAvecTraceParVar.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
 */
import { zero11 } from '../kernel/kernel'
import CListeObjets from './CListeObjets'
import CMacro from './CMacro'
import CSousListeObjets from './CSousListeObjets'
import CMacroAvecListe from './CMacroAvecListe'
export default CMacroAnimAvecTraceParVar

/**
 * Macro d'animation générée par point lié avec trace.
 * Les objets devant laisser une trace sont contenus dans une liste.
 * @constructor
 * @extends CMacroAvecListe
 * @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 la macro
 * @param {number} yNom  L'ordonnée d'affichage de la macro
 * @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} 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 {string} intitule  Le titre de la macro
 * @param {string} commentaireMacro  Eventuel commentaire explicatif.
 * @param {CListeObjets} listeAssociee  La liste contenant les objets qui laissent une trace.
 * @param {CVariableBornee} variableAssociee  Le point lié dont les positions génèrent la trace.
 * @param {boolean} unCycle  Si true l'animation se fait sur un seul cycle et s'arrête.
 * @param {boolean} effacementFinCycle  si true les traces d'objets sont effacées à la fin de chaque cycle.
 * @param {boolean} animationCyclique  true si animation cyclique (si non cyclique on repart au début).
 * @param {number} frequenceAnimationMacro  La fréquence d'animation en millièmes de seconde.
 * @param {number} nombrePointsPourAnimation
 * @param {number} dureeAnimation  Durée de l'animation en dixièmes de seconde ou null pour une animation
 * continue (dans ce cas un clic sur l'intitulé arrête l'animation).
 * @param {boolean} retourDepart  trus pour que le point lié reviene à son point de départ à la fin de l'animation.
 * @param {boolean} inverserSens  true pour que l'animation se fasse dans l'autre sens (Le sens usuel sur les cercles est
 * le sens trigonométrique direct).
 * @param {boolean} fixed true si l'affichage est punaisé et ne peut pas être capturé à la souris
 * @returns {CMacroAnimAvecTraceParVar}
 */
function CMacroAnimAvecTraceParVar (listeProprietaire, impProto, estElementFinal, couleur,
  xNom, yNom, decX, decY, masque, pointLie, taillePolice, effacementFond, couleurFond, alignementHorizontal,
  alignementVertical, intitule, commentaireMacro, listeAssociee, variableAssociee, unCycle,
  effacementFinCycle, animationCyclique, frequenceAnimationMacro,
  nombrePointsPourAnimation, dureeAnimation, retourDepart,
  inverserSens, fixed = false) {
  if (arguments.length !== 0) {
    if (arguments.length === 1) CMacroAvecListe.call(this, listeProprietaire)
    else {
      CMacroAvecListe.call(this, listeProprietaire, impProto, estElementFinal, couleur,
        xNom, yNom, decX, decY, masque, pointLie, taillePolice, effacementFond, couleurFond,
        alignementHorizontal, alignementVertical, intitule, commentaireMacro, listeAssociee, fixed)
      this.variableAssociee = variableAssociee
      this.unCycle = unCycle
      this.effacementFinCycle = effacementFinCycle
      this.animationCyclique = animationCyclique
      this.frequenceAnimationMacro = frequenceAnimationMacro
      this.nombrePointsPourAnimation = nombrePointsPourAnimation
      this.dureeAnimation = dureeAnimation
      this.retourDepart = retourDepart
      this.inverserSens = inverserSens
      this.listeDep = new CListeObjets(listeProprietaire)
    }
  }
}

CMacroAnimAvecTraceParVar.prototype = new CMacroAvecListe()
CMacroAnimAvecTraceParVar.prototype.constructor = CMacroAnimAvecTraceParVar
CMacroAnimAvecTraceParVar.prototype.superClass = 'CMacroAvecListe'
CMacroAnimAvecTraceParVar.prototype.className = 'CMacroAnimAvecTraceParVar'

CMacroAnimAvecTraceParVar.prototype.getClone = function (listeSource, listeCible) {
  const listeAssocieeClone = new CSousListeObjets()
  listeAssocieeClone.setImage(this.listeAssociee, listeSource, listeCible)
  const ind1 = listeSource.indexOf(this.variableAssociee)
  const ind2 = listeSource.indexOf(this.pointLie)
  const ind3 = listeSource.indexOf(this.impProto)
  return new CMacroAnimAvecTraceParVar(listeCible,
    listeCible.get(ind3, 'CImplementationProto'),
    this.estElementFinal, this.couleur, this.xNom, this.yNom, this.decX, this.decY, this.masque,
    listeCible.get(ind2, 'CPt'), this.taillePolice, this.effacementFond,
    this.couleurFond, this.alignementHorizontal, this.alignementVertical,
    this.intitule, this.commentaireMacro, listeAssocieeClone, listeCible.get(ind1, 'CVariableBornee'),
    this.unCycle, this.effacementFinCycle, this.animationCyclique,
    this.frequenceAnimationMacro, this.nombrePointsPourAnimation, this.dureeAnimation,
    this.retourDepart, this.inverserSens, this.fixed)
  // ptelb.listeDep = new CListeObjets(listeCible);
}
CMacroAnimAvecTraceParVar.prototype.depDe = function (p) {
  if (this.elementTestePourDependDe === p) return this.dependDeElementTeste
  return this.memDep(CMacroAvecListe.prototype.depDe.call(this, p) || this.variableAssociee.depDe(p))
}
CMacroAnimAvecTraceParVar.prototype.dependDePourBoucle = function (p) {
  return CMacroAvecListe.prototype.dependDePourBoucle.call(this, p) || this.variableAssociee.dependDePourBoucle(p)
}
CMacroAnimAvecTraceParVar.prototype.typeAnimation = function () {
  return CMacro.animationParTimer
}
CMacroAnimAvecTraceParVar.prototype.arretParClic = function () {
  return (this.dureeAnimation === 0) || this.unCycle
}
CMacroAnimAvecTraceParVar.prototype.metAJour = function () {
  CMacroAvecListe.prototype.metAJour.call(this)
  this.etablitListesInternes()
}
CMacroAnimAvecTraceParVar.prototype.etablitListesInternes = function () {
  this.listeDep.retireTout()
  this.listeDep.ajouteObjetsDependantsSauf(this.variableAssociee, this.listeProprietaire, this)
}
CMacroAnimAvecTraceParVar.prototype.executionPossible = function () {
  return true
}
CMacroAnimAvecTraceParVar.prototype.ajouteAntecedents = function (liste) {
  liste.ajouteElementsDe(this.listeAssociee)
}
CMacroAnimAvecTraceParVar.prototype.execute = function (svg, dimf, couleurFond) {
  this.listeProprietaire.initialiseTraces()
  this.valeurInitiale = this.variableAssociee.valeurActuelle
  this.valeurMini = this.variableAssociee.valeurMini
  this.valeurMaxi = this.variableAssociee.valeurMaxi
  this.pas = (this.valeurMaxi - this.valeurMini) / (this.nombrePointsPourAnimation - 1)
  if (this.inverserSens) this.pas = -this.pas
  this.valeur = this.inverserSens ? this.valeurMaxi : this.valeurMini
  this.valeur -= this.pas
  this.executionEnCours = true
  const timeDebut = Date.now()
  if (this.unCycle) this.timeFin = timeDebut + 100000000
  else if (this.dureeAnimation !== 0) this.timeFin = timeDebut + this.dureeAnimation * 100 // La durée est en dixièmes de secondes
  const t = this
  this.timer = setInterval(function () {
    CMacroAnimAvecTraceParVar.executePourTimer.call(t, svg, dimf, couleurFond)
  }, this.frequenceAnimationMacro)
}

// Modifié version 5.5.9 en utilisant zero11 au lieu de zero 13 car sinon certaines animations avec un seul cycle ne s'arrêtaient pas
/**
 * Fonction de callBack appelée par un timer dans execute()
 * @param {SVGElement} svg  Le svg de la figure.
 * @param {Dimf} dimf  Les dimensions du svg
 * @param {Color} couleurFond  La couleur de fond de la figure.
 * @returns {void}
 */
CMacroAnimAvecTraceParVar.executePourTimer = function (svg, dimf, couleurFond) {
  let d
  if (!this.executionEnCours) return
  this.valeur = this.valeur + this.pas
  if (zero11(this.valeur - this.valeurMaxi)) this.valeur = this.valeurMaxi
  else
    if (zero11(this.valeur - this.valeurMini)) this.valeur = this.valeurMini
  if (this.unCycle) {
    d = this.inverserSens ? this.valeur - this.valeurMini : this.valeur - this.valeurMaxi
    if (this.inverserSens) {
      if (d < 0) {
        this.timeFin = 0
        this.valeur = this.valeurMini
      }
    } else if (d > 0) {
      this.valeur = this.valeurMaxi
      this.timeFin = 0
    }
  } else {
    if (this.animationCyclique) {
      if (this.inverserSens) {
        if (this.valeur < this.valeurMini) {
          this.valeur = this.valeurMaxi
          if (this.effacementFinCycle) this.effacementTraces = true
        }
      } else if (this.valeur > this.valeurMaxi) {
        this.valeur = this.valeurMini
        if (this.effacementFinCycle) this.effacementTraces = true
      }
    } else {
      if (this.valeur < this.valeurMini) {
        this.pas = -this.pas
        this.valeur = this.valeurMini
        if (this.effacementFinCycle) this.effacementTraces = true
      } else if (this.valeur > this.valeurMaxi) {
        this.pas = -this.pas
        this.valeur = this.valeurMaxi
        if (this.effacementFinCycle) this.effacementTraces = true
      }
    }
  }
  if (this.effacementTraces) {
    this.listeProprietaire.deleteTraces()
    this.effacementTraces = false
  }
  this.variableAssociee.donneValeur(this.valeur)
  // On déplace le point lié vers sa nouvelle position
  this.listeDep.positionne(false, dimf)
  this.listeProprietaire.addTraces(this.listeAssociee)
  // this.listeProprietaire.update(svg, couleurFond, transparence, true); // Modifié version 4.9.2
  // Ligne suivante modifié version 6.4.8 (ajout du dernier paramètre)
  this.listeDep.update(svg, couleurFond, true, true)
  const time = Date.now() // Raccourci pour (new Date()).getTime()
  /*
  if ((this.dureeAnimation !== 0) && (time > this.timeFin))
    this.termineAction(svg, dimf, couleurFond, transparence);
    */
  if (this.unCycle) {
    if (this.inverserSens) {
      if (zero11(this.valeur - this.valeurMini) || (this.valeur < this.valeurMini)) this.termineAction(svg, dimf, couleurFond)
    } else if (zero11(this.valeur - this.valeurMaxi) || (this.valeur > this.valeurMaxi)) this.termineAction(svg, dimf, couleurFond)
  } else if ((this.dureeAnimation !== 0) && (time > this.timeFin)) this.termineAction(svg, dimf, couleurFond)
}
CMacroAnimAvecTraceParVar.prototype.termineAction = function (svg, dimf, couleurFond) {
  if (this.timer !== null) clearInterval(this.timer)
  this.executionEnCours = false
  if (this.retourDepart) this.variableAssociee.donneValeur(this.valeurInitiale)
  else this.variableAssociee.donneValeur(this.inverserSens ? this.valeurMini : this.valeurMaxi)
  this.listeDep.positionne(false, dimf)
  // Ligne suivante modifié version 6.4.8 (ajout du dernier paramètre)
  this.listeDep.update(svg, couleurFond, true, true)
  this.passageMacroSuiv(svg, dimf, couleurFond)
}
CMacroAnimAvecTraceParVar.prototype.read = function (inps, list) {
  CMacroAvecListe.prototype.read.call(this, inps, list)
  this.unCycle = inps.readBoolean()
  this.effacementFinCycle = inps.readBoolean()
  this.animationCyclique = inps.readBoolean()
  this.frequenceAnimationMacro = inps.readInt()
  this.nombrePointsPourAnimation = inps.readInt()
  this.dureeAnimation = inps.readInt()
  const ind1 = inps.readInt()
  this.variableAssociee = list.get(ind1, 'CVariableBornee')
  this.retourDepart = inps.readBoolean()
  this.inverserSens = inps.readBoolean()
  // this.listeDep = new CListeObjets(list.uniteAngle, list.pointeurLongueurUnite);
  // Pour arrêter la macro quand elle n'effectue qu'un seul cycle
  // il ne faut pas que dureeAnimation soit nul;
  if (this.unCycle) this.dureeAnimation = 1
  if (list.className !== 'CPrototype') this.listeDep = new CListeObjets(this.listeProprietaire)
}
CMacroAnimAvecTraceParVar.prototype.write = function (oups, list) {
  CMacroAvecListe.prototype.write.call(this, oups, list)
  oups.writeBoolean(this.unCycle)
  oups.writeBoolean(this.effacementFinCycle)
  oups.writeBoolean(this.animationCyclique)
  oups.writeInt(this.frequenceAnimationMacro)
  oups.writeInt(this.nombrePointsPourAnimation)
  oups.writeInt(this.dureeAnimation)
  const ind1 = list.indexOf(this.variableAssociee)
  oups.writeInt(ind1)
  oups.writeBoolean(this.retourDepart)
  oups.writeBoolean(this.inverserSens)
}