Intégration d'un Graphique Echarts en Temps Réel avec Vue 2

Contexte et objectif

Implémenter une fonctionnailté où le survol d'un élément déclenche l'affichage d'une infobulle contenant un graphique Echarts, dont les données se mettent à jour dynamiquement.

Cette solution s'appuie sur Vue.js 2 et la bibliothèque Echarts. L'architecture suppose une hiérarchie de composants : un composant parent gère l'état des données, un composant intermédiaire gère l'interaction et la logique d'affichage, et un composant enfant est dédié au rendu du graphique.

Architecture de gestion des données

Le composant parent centralise les données et les transmet aux enfants. La communication descendante s'effectue via les props, tandis qu'une méthode exposée permet au parent d'initialiser le lien avec l'enfant.


<!-- Composant Parent -->
<template>
  <div id="app">
    <ComposantIntermediaire ref="refComposant"></ComposantIntermediaire>
  </div>
</template>

<script>
import ComposantIntermediaire from './ComposantIntermediaire.vue';

export default {
  name: 'App',
  components: { ComposantIntermediaire },
  data() {
    return {
      donneesGlobales: {
        serieA: null,
        serieB: null
      }
    };
  },
  mounted() {
    this.initialiserComposants();
  },
  methods: {
    initialiserComposants() {
      const instance = this.$refs.refComposant;
      if (instance) {
        instance.lierDonneesPartagees(this.donneesGlobales);
      }
    }
  }
};
</script>

Copmosant intermédiaire : interaction et liaison

Ce composant écoute les événements de souris sur des zones définies. Il positionne dynamiquement l'infobulle et orchestre la mise à jour du graphique enfant lorsque les données partagées changent.


<!-- ComposantIntermediaire.vue -->
<template>
  <div class="zone-graphique">
    <div
      class="gachette"
      @mouseenter="afficherGraphiqueBulle($event, 'A')"
      @mouseleave="masquerGraphiqueBulle"
    >
      Zone A
    </div>
    <div
      class="gachette"
      @mouseenter="afficherGraphiqueBulle($event, 'B')"
      @mouseleave="masquerGraphiqueBulle"
    >
      Zone B
    </div>

    <div
      class="infobulle"
      v-show="infobulleVisible"
      :style="{ left: positionX + 'px', top: positionY + 'px' }"
    >
      <GraphiqueEcharts ref="refGraphique"></GraphiqueEcharts>
    </div>
  </div>
</template>

<script>
import GraphiqueEcharts from './GraphiqueEcharts.vue';

export default {
  name: 'ComposantIntermediaire',
  components: { GraphiqueEcharts },
  data() {
    return {
      typeSelectionne: null,
      infobulleVisible: false,
      positionX: 0,
      positionY: 0,
      donneesGraphique: null,
      donneesPartagees: {
        serieA: { label: 'Catégorie A', valeurs: [10, 25, 18, 30, 22] },
        serieB: { label: 'Catégorie B', valeurs: [15, 8, 22, 12, 28] }
      }
    };
  },
  watch: {
    donneesPartagees: {
      handler(nouvellesDonnes) {
        if (nouvellesDonnes && this.infobulleVisible) {
          this.mettreAJourDonneesGraphique();
        }
      },
      deep: true
    }
  },
  methods: {
    lierDonneesPartagees(data) {
      if (data) {
        this.donneesPartagees = data;
      }
    },

    afficherGraphiqueBulle(event, type) {
      this.typeSelectionne = type;
      this.mettreAJourDonneesGraphique();

      const elementCible = event.currentTarget;
      const rect = elementCible.getBoundingClientRect();
      this.positionX = rect.left;
      this.positionY = rect.bottom + 10;

      this.infobulleVisible = true;
    },

    masquerGraphiqueBulle() {
      this.infobulleVisible = false;
      this.donneesGraphique = null;
      const graphique = this.$refs.refGraphique;
      if (graphique) {
        graphique.viderGraphique();
      }
    },

    mettreAJourDonneesGraphique() {
      const source = this.typeSelectionne === 'A' ?
        this.donneesPartagees.serieA :
        this.donneesPartagees.serieB;

      this.donneesGraphique = source;

      const graphique = this.$refs.refGraphique;
      if (graphique) {
        graphique.initialiserGraphique(this.donneesGraphique);
      }
    }
  }
};
</script>

Composant anfant : le graphique Echarts

Ce composant encapsule l'instance Echarts. Il expose des méthodes pour l'initialisation, le rendu des données et le nettoyage des ressources.


<!-- GraphiqueEcharts.vue -->
<template>
  <div class="conteneur-echarts">
    <div ref="elementGraphique"></div>
  </div>
</template>

<script>
import * as echarts from 'echarts';

export default {
  name: 'GraphiqueEcharts',
  data() {
    return {
      instanceGraphique: null,
      donneesRecues: null
    };
  },
  beforeDestroy() {
    this.nettoyerGraphique();
    window.removeEventListener('resize', this.redimensionner);
  },
  methods: {
    initialiserGraphique(donnees) {
      if (!donnees) return;

      if (!this.instanceGraphique) {
        this.instanceGraphique = echarts.init(this.$refs.elementGraphique);
        window.addEventListener('resize', this.redimensionner);
      }

      this.donneesRecues = donnees;
      this.construireGraphique(this.donneesRecues.valeurs);
    },

    construireGraphique(valeursY) {
      const categoriesX = ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'];

      const option = {
        backgroundColor: '#2c343c',
        xAxis: {
          type: 'category',
          data: categoriesX,
          axisLabel: { color: '#aaa' }
        },
        yAxis: {
          type: 'value',
          axisLabel: { color: '#aaa' },
          splitLine: { lineStyle: { type: 'dashed', color: '#444' } }
        },
        series: [{
          name: this.donneesRecues.label,
          type: 'line',
          data: valeursY,
          smooth: true,
          areaStyle: { color: 'rgba(64, 158, 255, 0.3)' },
          itemStyle: { color: '#409eff' },
          lineStyle: { width: 2 }
        }]
      };

      this.instanceGraphique.setOption(option, true);
    },

    redimensionner() {
      if (this.instanceGraphique) {
        this.instanceGraphique.resize();
      }
    },

    viderGraphique() {
      if (this.instanceGraphique) {
        this.instanceGraphique.clear();
        this.instanceGraphique.dispose();
        this.instanceGraphique = null;
      }
    },

    nettoyerGraphique() {
      this.viderGraphique();
    }
  }
};
</script>

Étiquettes: Vue.js 2 ECharts JavaScript composants Données en temps réel

Publié le 26 juin à 21h06