Graphiques groupés ET empilés

Bonjour,

Après avoir infiniment pesté, maugréé et vitupéré Jeedom pour ses aspects horriblement geek, je suis heureux de vous présenter enfin une contribution positive sur les graphiques groupés ET empilés:

ça marche ! Miracle, Hosanna…

J’ai donc employé les graphiques HighCharts en me fondant sur l’utilisation du plugin plugin-htmldisplay . Inutile de vous dire que je n’y serai jamais parvenu sans l’aide massive de notre nouvel ami à tous, ChatGPT qui a très largement contribué au code final que voici :

<!DOCTYPE html>
<html lang="fr">
  <head>
    <meta charset="“UTF-8”" />
  </head>
  <body>
    <div style="text-align:center; margin-bottom: 20px;">
  <label for="dateEnd">Date de fin :</label>
  <input type="date" id="dateEnd">

  <label for="duration">Durée (jours) :</label>
  <input type="number" id="duration" min="1" value="7">

  <button onclick="chargerDonnees()">Mettre à jour</button>
</div>


<style>

.highcharts-figure,
.highcharts-data-table table {
    min-width: 310px;
    max-width: 800px;
    margin: 1em auto;
}

#container {
    height: 400px;
}

.highcharts-data-table table {
    font-family: Verdana, sans-serif;
    border-collapse: collapse;
    border: 1px solid var(--highcharts-neutral-color-10, #e6e6e6);
    margin: 10px auto;
    text-align: center;
    width: 100%;
    max-width: 500px;
}

.highcharts-data-table caption {
    padding: 1em 0;
    font-size: 1.2em;
    color: var(--highcharts-neutral-color-60, #666);
}

.highcharts-data-table th {
    font-weight: 600;
    padding: 0.5em;
}

.highcharts-data-table td,
.highcharts-data-table th,
.highcharts-data-table caption {
    padding: 0.5em;
}

.highcharts-data-table thead tr,
.highcharts-data-table tbody tr:nth-child(even) {
    background: var(--highcharts-neutral-color-3, #f7f7f7);
}

.highcharts-description {
    margin: 0.3rem 10px;
}
</style>

<figure class="highcharts-figure">
    <div id="container"></div>
    <p class="highcharts-description">
    </p>
         

    <script>
function getYesterdayDate() {
  const d = new Date();
  d.setDate(d.getDate() - 1);
  return d.toISOString().split('T')[0]; // Format YYYY-MM-DD
}

document.addEventListener("DOMContentLoaded", () => {
  // Valeurs par défaut : hier et 7 jours
  document.getElementById("dateEnd").value = getYesterdayDate();
  chargerDonnees();
});

function chargerDonnees() {
  const dateEnd = document.getElementById("dateEnd").value;
  const duration = parseInt(document.getElementById("duration").value, 10);

  if (!dateEnd || isNaN(duration)) {
    alert("Veuillez saisir une date et une durée valides.");
    return;
  }

  const endDate = new Date(dateEnd);
  const startDate = new Date(endDate);
  startDate.setDate(endDate.getDate() - duration + 1); // inclusif

  const dateStartStr = startDate.toISOString().split('T')[0];
  const dateEndStr = endDate.toISOString().split('T')[0];

  // Réinitialisation
  var timestamps = [], prod_jour = [], cons_jour = [], export_jour = [], import_jour = [];
  var chargements = 0;

  function essayerAfficherGraphique() {
    if (chargements < 4) return;

    const prod_series = timestamps.map((ts, i) => [ts, prod_jour[i]]);
    const cons_series = timestamps.map((ts, i) => [ts, cons_jour[i]]);
    const export_series = timestamps.map((ts, i) => [ts, export_jour[i]]);
    const import_series = timestamps.map((ts, i) => [ts, import_jour[i]]);

    Highcharts.setOptions({
      lang: {
        months: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin',
          'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],
        weekdays: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
        shortMonths: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin',
          'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.']
      }
    });

    Highcharts.chart('container', {
      chart: { type: 'column' },
      title: { text: 'Production et consommation électrique', align: 'left' },
      xAxis: {
        type: 'datetime',
        labels: { format: '{value:%e %b}' }
      },
      yAxis: {
        min: 0,
        title: { text: 'Énergie (kWh)' },
        stackLabels: { enabled: true }
      },
      tooltip: {
        xDateFormat: '%A %e %B %Y',
        shared: true
      },
      plotOptions: {
        column: { stacking: 'normal' }
      },
      series: [{
  name: 'Production',
  data: prod_series,
  stack: 'In',
  color: '#00aa00' // vert
}, {
  name: 'Importation',
  data: import_series,
  stack: 'In',
  color: '#ff0000' // rouge vif
}, {
  name: 'Consommation',
  data: cons_series,
  stack: 'Out',
  color: '#0000ff' // bleu
}, {
  name: 'Exportation',
  data: export_series,
  stack: 'Out',
  color: '#800080' // violet
}]
    });
  }

  // Chargement production
  jeedom.history.get({
    cmd_id: 42,
    dateStart: dateStartStr,
    dateEnd: dateEndStr,
    success: function (result) {
      for (let i = 0; i < result.data.length; i++) {
        const d = new Date(result.data[i][0]);
        timestamps.push(d.getTime());
        prod_jour.push(Math.floor(result.data[i][1] / 1000));
      }
      chargements++;
      essayerAfficherGraphique();
    }
  });

  // Chargement consommation
  jeedom.history.get({
    cmd_id: 50,
    dateStart: dateStartStr,
    dateEnd: dateEndStr,
    success: function (result) {
      for (let i = 0; i < result.data.length; i++) {
        cons_jour.push(Math.floor(result.data[i][1] / 1000));
      }
      chargements++;
      essayerAfficherGraphique();
    }
  });

  // Chargement exportation
  jeedom.history.get({
    cmd_id: 65,
    dateStart: dateStartStr,
    dateEnd: dateEndStr,
    success: function (result) {
      for (let i = 0; i < result.data.length; i++) {
        export_jour.push(Math.floor(result.data[i][1] / 1000));
      }
      chargements++;
      essayerAfficherGraphique();
    }
  });

  // Chargement importation
  jeedom.history.get({
    cmd_id: 66,
    dateStart: dateStartStr,
    dateEnd: dateEndStr,
    success: function (result) {
      for (let i = 0; i < result.data.length; i++) {
        import_jour.push(Math.floor(result.data[i][1] / 1000));
      }
      chargements++;
      essayerAfficherGraphique();
    }
  });
}
</script>



      
 </figure>
</body>
</html>  

Deux remarques sur le code:

  • Inutile (et même « impossible ») de charger les librairies externes HighCharts comme c’était fait ici. Cela provoque une erreur « Directive de Content Security Policy ». HighCharts étant désormais intégré à Jeedom, nul besoin de ces appels externes comme expliqué par @Aurelien
  • Je n’ai pas réussi (et ChatGPT non plus) à faire en sorte que le graphique soit peuplé par défaut sur un créneau de dates données (par exemple de J-7 à J-1). C’est une affaire de chargement asynchrone mais le graphique « arrive » vide et je dois préciser les dates « à la main » pour qu’il se peuple.

Une remarque sur le contenu des énergies journalières affichées:

  • Je me serais attendu à ce que production + importation soit un peu supérieur à consommation + exportation, à cause des pertes. Or j’ai systématiquement le contraire. Je n’ai pas d’explication satisfaisante mais je vais vérifier que les données intégrées (en sommes par jour) considèrent toutes bien les mêmes périodes de temps.

Voilà, merci à tous ceux qui ont supporté avec navrement mes errements et commentaires doux-amers. Ceci dit, avant que Jeedom devienne un produit grand public, il risque de se passer du temps.

En espérant que cela serve.

2 « J'aime »