web-dev-qa-db-fra.com

Vue Chart.js - simple point / ligne sur le graphique à barres

J'aurais besoin d'ajouter un simple point/ligne verticale sur mon graphique bar qui a une valeur X dynamique et 0 pour la valeur Y. Aperçu de ce dont j'ai besoin (le point rouge):

enter image description here

Où les valeurs vertes sont dynamiques.

Aperçu de mon état actuel:

enter image description here

Où 3,30 doit être la coordonnée X du point - [3,30, 0].

J'utilise Graphique vue pour les graphiques et j'ai essayé d'en créer un mixte avec les bar et scatter mais scatter nécessite type: 'linear' car c'est xAxis qui ne correspond pas à mes besoins pour le graphique bar.

J'ai donc essayé avec chartjs-plugin-annotation et c'est le type box qui accepte les "coordonnées" mais le problème ici est que la valeur X doit être une valeur fixe sur l'axe X (objet labels). Si je mets pour l'axe X [3,0] cela fonctionnera, mais s'il y a un nombre décimal, comme [3,5, 0], cela ne fonctionnera pas.


  // data
  options: {
    responsive: true,
    maintainAspectRatio: false,
    legend: {
      display: false
    },
    scales: {
      yAxes: [{
        ticks: {
          min: 0,
          max: 1,
          stepSize: 0.1
        }
      }]
    }
  }

  // computed 
  labels: [1, 2, 3, 4, 5, 6], // fixed value, there are always 6 bars
  datasets: [
    {
      label: 'Values',
      backgroundColor: '#f89098',
      data: this.tableInputValues // array of decimal values
    }
  ]

Donc, ma question est de savoir comment placer un point "simple", ou une ligne verticale, sur un graphique à barres Chart.js où le point a une valeur dynamique pour l'axe X -> [dynamic valeur, 0].

Pour info - il s'agit de valeur attendue

13
Vucko

Pour autant que je comprends Vue Le graphique fonctionne à l'aide de canvas (comme vu sur Page de démonstration ).
Donc, ma suggestion ici est de récupérer le nœud de canevas représentant le graphique dans votre DOM et d'écrire dynamiquement le point souhaité. Par exemple:

var c = document.getElementById("bar-chart");   //hereby assuming canvas named "bar-chart"
var ctx = c.getContext("2d");
ctx.fillStyle = "#ff0000";                     //red color for the dot
ctx.beginPath();
let yPosition = c.height - 5;                 //fixed y position
let xPosition = 35;                          //that's the dynamic expected value
ctx.arc(xPosition, yPosition, 2.5, 0, 2 * Math.PI);
ctx.fill();

Ici vous trouverez une démo montrant comment y parvenir en utilisant Vue. Dans ce scénario, vous devez encapsuler le code pour dessiner un point sur le canevas dans un crochet afterDraw. Ce crochet doit être attaché au composant graphique en tant que plugin, donc comme ceci:

...
mounted () { 
   //adding the plugin to draw the red dot
   this.addPlugin({
    id: 'chart-plugin',
    afterDraw: function (chart) {
       var c = chart.canvas;   
       var ctx = c.getContext("2d");
       ctx.fillStyle = "#ff0000";                     
       ctx.beginPath();
       let xPosition = 742; //x positioning to be calculated according to your needs
       let yPosition = c.height - 28;                                       
       ctx.arc(xPosition, yPosition, 3, 0, 2 * Math.PI);
       ctx.fill();
    }
  });

  //actual chart rendering
  this.renderChart({ 
    ...
  });
}
...

Par souci d'exhaustivité, ici vous trouverez la liste de tous les hooks disponibles de l'API du plugin Chart.js.

7
P3trur0

Ceci est ma solution pour votre problème https://jsfiddle.net/huynhsamha/e54djwxp/

Et c'est une capture d'écran pour le résultat

enter image description here

Dans ma solution, j'utilise type="line" et les deux axes x et y avec type="linear". J'ajoute également la propriété options à <chart> pour utiliser options dans ChartJS

<div id="vue">
  <chart type="line" :data="data" :options="options"></chart>
</div>

options configurera l'axe x et l'axe y pour rendre les points de données et la valeur attendue:

      options: {
        scales: {
            xAxes: [{
            type: 'linear',
            ticks: {
                min: 1,
                max: 6,
                stepSize: 1
            }
          }],
           yAxes: [{
            type: 'linear',
            ticks: {
                min: 0,
                max: 1,
                stepSize: 0.1
            }
            }]
        }
      }

Et le data aura 2 datasets. Le premier est les points de données, utilisez le type line et le second est la valeur attendue qui utilise le type bubble.

      data: {
        datasets: [{
            label: 'Frequency Data',
            data: dataPoints.map(({ val, freq }) => ({
                x: val,
              y: freq
            })),
            backgroundColor: 'rgba(72, 202, 59, 0.4)',
            borderColor: 'rgba(72, 202, 59, 1)'
        }, {
            label: 'Expected Value',
            type: 'bubble',
            data: [{ 
                x: expectedValue, 
              y: 0, 
              r: 8 // radius
            }],
            backgroundColor: 'rgba(255, 68, 0, 0.4)',
            borderColor: 'rgba(255, 68, 0, 1)'
        }]
        },

Dans datasets, nous avons dataPoints et expectedValue, il sera récupéré depuis l'API pour obtenir vos points de données. Je simule également l'API simple pour les points de données:

// simulate the API to get data points
const retrieveData = () => [
    { val: 1, freq: 0.15 },
    { val: 2, freq: 0.25 },
    { val: 3, freq: 0.3 },
    { val: 4, freq: 0.2 },
    { val: 5, freq: 0.1 },
    { val: 6, freq: 0.45 }
]


// fetch your data here, return array of JSON { val, freg }
const dataPoints = retrieveData() || [];

// calculate expected value = sum( val * freq ) each i in dataPoints
const expectedValue = dataPoints.reduce((cur, { val, freq }) => cur + val * freq, 0).toFixed(4);

Vous pouvez exécuter l'extrait de code ou exécuter sur le violon https://jsfiddle.net/huynhsamha/e54djwxp/92/

<script async src="//jsfiddle.net/huynhsamha/e54djwxp/92/embed/js,html,css,result/dark/"></script>
2
huynhsamha