◆ Portail Antalaha

Annuaire › Code ouvert

Pluviométrie mensuelle - tableau de bord (p5.js)

tutorial · Voir le site ↗
Connectez-vous pour copier ce site

Code publié par son auteur, en lecture seule. « Copier dans mon espace » crée un nouveau site à vous (non publié) que vous pouvez modifier librement.

js/interaction.js · 5.3 Ko

/* ============================================================
   interaction.js - souris, doigt et infobulle
   ============================================================
   p5 appelle automatiquement certaines fonctions quand
   l'utilisateur agit (si on les définit) :
     mouseMoved()   : la souris bouge (sans bouton enfoncé)
     mouseDragged() : la souris bouge bouton enfoncé
     mousePressed() : clic
     touchStarted() : un doigt se pose sur l'écran
     touchMoved()   : le doigt glisse
   Toutes déterminent le MÊME résultat : "quel mois est sélectionné ?"
   (variable globale indexSelection ; -1 = aucun).

   Variables p5 utiles :
     mouseX, mouseY : position de la souris DANS le canevas
     touches        : tableau des doigts posés ; touches[0].x / .y
   ============================================================ */

/* ------------------------------------------------------------
   indexDepuisPosition(px, py)
   But : trouver quel mois se trouve sous un point du canevas.
   Paramètres : px, py = coordonnées en pixels dans le canevas
   Retour : un entier de 0 à 11, ou -1 si le point est hors du graphique
   ------------------------------------------------------------ */
function indexDepuisPosition(px, py) {
  // Hors du canevas ?
  if (px < 0 || px > width || py < 0 || py > height) return -1;
  // Hors de la zone horizontale du tracé (dans les marges) ?
  if (px < zone.x0 || px > zone.x1) return -1;
  // Division par la largeur d'une colonne -> numéro de colonne.
  // floor() arrondit vers le bas ; constrain() évite 12 si px == zone.x1.
  return constrain(floor((px - zone.x0) / zone.colonne), 0, 11);
}

/* ------------------------------------------------------------
   mettreAJourSelectionSouris()
   But : mémoriser le mois sous la souris.
   ------------------------------------------------------------ */
function mettreAJourSelectionSouris() {
  indexSelection = indexDepuisPosition(mouseX, mouseY);
}

/* ------------------------------------------------------------
   mettreAJourSelectionTactile()
   But : mémoriser le mois sous le (premier) doigt.
   Si aucun doigt n'est posé, on ne change rien : la sélection
   reste affichée après avoir levé le doigt (pratique sur mobile).
   ------------------------------------------------------------ */
function mettreAJourSelectionTactile() {
  if (touches.length > 0) {
    indexSelection = indexDepuisPosition(touches[0].x, touches[0].y);
  }
}

// --- Fonctions appelées automatiquement par p5 ---
function mouseMoved() { mettreAJourSelectionSouris(); }
function mouseDragged() { mettreAJourSelectionSouris(); }
function mousePressed() { mettreAJourSelectionSouris(); }
function touchStarted() { mettreAJourSelectionTactile(); }   // on ne renvoie pas false : la page peut défiler
function touchMoved() { mettreAJourSelectionTactile(); }

/* ------------------------------------------------------------
   dessinerSurvol()
   But : colorer en arrière-plan la colonne sélectionnée.
   ------------------------------------------------------------ */
function dessinerSurvol() {
  if (indexSelection < 0) return;
  noStroke();
  fill(242, 160, 7, 38);                         // orange très transparent
  rect(zone.x0 + indexSelection * zone.colonne, zone.y0, zone.colonne, zone.haut);
}

/* ------------------------------------------------------------
   dessinerInfobulle(valeurs)
   But : dessiner la bulle d'information près du mois sélectionné.
   Paramètre : valeurs = valeurs ANIMÉES (pour que la bulle suive
               le sommet de la barre pendant l'animation).
   On affiche pourtant la valeur CIBLE (la vraie), pas la valeur
   en train de grandir.
   ------------------------------------------------------------ */
function dessinerInfobulle(valeurs) {
  if (indexSelection < 0) return;

  const i = indexSelection;
  const vraie = valeursCibles[i];

  // Lignes de texte de l'infobulle
  const lignes = [];
  lignes.push(MOIS_COMPLETS[i] + (choixCourant === 'moyenne' ? ' (moyenne)' : ' ' + choixCourant));
  lignes.push(Math.round(vraie) + ' mm');
  if (choixCourant !== 'moyenne') {
    const ref = moyenneSerie[i];
    const ecart = Math.round((vraie - ref) / ref * 100);
    lignes.push((ecart >= 0 ? '+' : '') + ecart + ' % par rapport à la moyenne');
  }
  lignes.push('valeur d\'illustration');

  // Taille de la bulle : on MESURE la ligne la plus large avec textWidth().
  textFont(POLICE);
  textSize(12);
  let largeurMax = 0;
  for (const l of lignes) largeurMax = Math.max(largeurMax, textWidth(l));
  const margeInt = 8;
  const interligne = 16;
  const w = largeurMax + margeInt * 2;
  const h = lignes.length * interligne + margeInt * 2 - 4;

  // Position : au-dessus du sommet de la barre, centrée sur la colonne,
  // mais TOUJOURS à l'intérieur du canevas grâce à constrain().
  const ancreX = xCentreColonne(i);
  const ancreY = yDepuisValeur(valeurs[i]);
  const bx = constrain(ancreX - w / 2, 4, width - w - 4);
  const by = constrain(ancreY - h - 12, 4, height - h - 4);

  // Fond arrondi
  noStroke();
  fill(COULEURS.infobulleFond);
  rect(bx, by, w, h, 6);

  // Textes : 1re ligne en gras, 2e ligne plus grande
  fill(COULEURS.infobulleTexte);
  textAlign(LEFT, TOP);
  for (let k = 0; k < lignes.length; k++) {
    textStyle(k <= 1 ? BOLD : NORMAL);
    textSize(k === 1 ? 14 : 12);
    text(lignes[k], bx + margeInt, by + margeInt - 2 + k * interligne);
  }
  textStyle(NORMAL);
}