web-dev-qa-db-fra.com

Camembert HTML5

J'essaie de créer un graphique à secteurs simple, comme illustré dans le graphique ci-dessous:

enter image description here

Le graphique montrera les résultats pour un quiz où un utilisateur peut choisir soit a, b ou c. Ce sont 10 questions et l’utilisateur ne peut choisir qu’une option par question.

Ce que je veux faire, c'est montrer le graphique à secteurs avec chaque segment représentant un pourcentage de 100% en transmettant les valeurs de a, b ou c.

J'ai les éléments suivants jusqu'à présent:

var greenOne = "#95B524";
var greenTwo = "#AFCC4C";
var greenThree = "#C1DD54";

function CreatePieChart() {
  var chart = document.getElementById('piechart');
  var canvas = chart.getContext('2d');
  canvas.clearRect(0, 0, chart.width, chart.height);

  var total = 100;

  var a = 3;
  var b = 4;
  var c = 3;

  for (var i = 0; i < 3; i++) {
    canvas.fillStyle = "#95B524";
    canvas.beginPath();
    canvas.strokeStyle = "#fff";
    canvas.lineWidth = 3;
    canvas.arc(100, 100, 100, 0, Math.PI * 2, true);
    canvas.closePath();
    canvas.stroke();
    canvas.fill();
  }
}
CreatePieChart();
<canvas id="piechart" width="200" height="200"></canvas>

Les couleurs étant spécifiques à la taille du segment, le vert est utilisé pour le plus grand et le vert trois pour le plus petit.

Merci

21
Cameron

Même après une recherche sur Google et une triple vérification de mes valeurs en radians, etc. J'avais toujours eu des problèmes avec cela, alors j'ai créé un jsFiddle pour que les gens puissent jouer avec comme exemple réel et posterai le code ci-dessous aussi.

var canvas = document.getElementById("can");
var ctx = canvas.getContext("2d");
var lastend = 0;
var data = [200, 60, 15]; // If you add more data values make sure you add more colors
var myTotal = 0; // Automatically calculated so don't touch
var myColor = ['red', 'green', 'blue']; // Colors of each slice

for (var e = 0; e < data.length; e++) {
  myTotal += data[e];
}

for (var i = 0; i < data.length; i++) {
  ctx.fillStyle = myColor[i];
  ctx.beginPath();
  ctx.moveTo(canvas.width / 2, canvas.height / 2);
  // Arc Parameters: x, y, radius, startingAngle (radians), endingAngle (radians), antiClockwise (boolean)
  ctx.arc(canvas.width / 2, canvas.height / 2, canvas.height / 2, lastend, lastend + (Math.PI * 2 * (data[i] / myTotal)), false);
  ctx.lineTo(canvas.width / 2, canvas.height / 2);
  ctx.fill();
  lastend += Math.PI * 2 * (data[i] / myTotal);
}
<canvas id="can" width="200" height="200" />

34
Alex W

J'aime la réponse précédente, mais j’ai eu le sentiment qu’il manquait de clarté dans le code et qu’il ne traitait pas vraiment de l’utilisation des étiquettes. 

J'ai déplacé les valeurs dans un tableau d'objet de données pour une déclaration facile. D'autres valeurs, telles que pourcentage, que j'ai explicitement déclarées en tant que propriété de l'objet de données ou en tant que variable distincte. Je pense que cela facilite la lecture.

La refactorisation a également permis de lier plus facilement les valeurs aux zones de saisie si cela vous intéressait.

Pour voir ce que je veux dire et jouer avec les valeurs, consultez ce CodePen: http://codepen.io/zfrisch/pen/pRbZeb

  var data = [{
    label: "one",
    value: 100,
    color: 'white'
  }, {
    label: "two",
    value: 100,
    color: 'skyBlue'
  }, {
    label: "three",
    value: 100,
    color: 'yellow'
  }];

  var total = 0;
  for (obj of data) {
    total += obj.value;
  }

  var canvas = document.getElementById('myCanvas');
  var ctx = canvas.getContext('2d');
  var previousRadian;
  var middle = {
    x: canvas.width / 2,
    y: canvas.height / 2,
    radius: canvas.height / 2,
  };
  
   //background
  ctx.beginPath();
  ctx.arc(middle.x, middle.y, middle.radius, 0, 2 * Math.PI);
  ctx.closePath();
  ctx.stroke();
  ctx.fillStyle = "black";
  ctx.fill();
   //end of background

  for (obj of data) {
    previousRadian = previousRadian || 0;
    obj.percentage = parseInt((obj.value / total) * 100)
    
    ctx.beginPath();
    ctx.fillStyle = obj.color;
    obj.radian = (Math.PI * 2) * (obj.value / total);
    ctx.moveTo(middle.x, middle.y);
    //middle.radius - 2 is to add border between the background and the pie chart
    ctx.arc(middle.x, middle.y, middle.radius - 2, previousRadian, previousRadian + obj.radian, false);
    ctx.closePath();
    ctx.fill();
    ctx.save();
    ctx.translate(middle.x, middle.y);
    ctx.fillStyle = "black";
    ctx.font = middle.radius / 10 + "px Arial";
    ctx.rotate(previousRadian + obj.radian);
    var labelText = "'" + obj.label + "' " + obj.percentage  + "%";
    ctx.fillText(labelText, ctx.measureText(labelText).width / 2, 0);
    ctx.restore();

    previousRadian += obj.radian;
  }
<canvas id="myCanvas" width="500" height="500" ></canvas>

4
zfrisch

J'ai eu le même problème avant, mais j'ai pu résoudre ce problème plus tard. 

Ce qui me manquait, c’était de dessiner un arc dans son contexte et d’essayer de le remplir. La couleur s’est alors répandue sur tout le cercle car le contexte n’était lié qu’à une ligne de rayon allant du centre au point de départ l'arc pour délimiter le contexte. 

Mais il n’y avait pas d’autre limite entre le bout d’Arch et le centre, dès que j’ai tracé cette ligne en utilisant ce qui suit:

ctx.lineTo(center coordinates of circle);

J'ai une limite complète de tarte, donc maintenant, si je remplis la couleur dans son contexte, elle ne sera pas étendue à l'intérieur du cercle mais se limitera à cette tarte. 

0
Akshat Maltare