How can I show a subset of pie parts data in Chart.JS while maintaining a superset when falling?

I have a pie chart that looks like it soars above a piece of cake:

enter image description here

Except for the desires on the right, and not on the top , I am quite satisfied with this, but I want only the percentage value to display "all the time" in the pieces of the cake - and still there is <name> (<%val>): <data> displayed when you hover over.

In other words, I want the cake to look something like this:

enter image description here

How can I break this piece of data (percentage) and draw it on every piece of cake?

Here is the code that I use so far:

 var formatter = new Intl.NumberFormat("en-US"); var data = { labels: [ "Bananas (18%)", "Lettuce, Romaine (14%)", "Melons, Watermelon (10%)", "Pineapple (10%)", "Berries (10%)", "Lettuce, Spring Mix (9%)", "Broccoli (8%)", "Melons, Honeydew (7%)", "Grapes (7%)", "Melons, Cantaloupe (7%)" ], datasets: [ { data: [2755, 2256, 1637, 1608, 1603, 1433, 1207, 1076, 1056, 1048], backgroundColor: [ "#FFE135", "#3B5323", "#fc6c85", "#ffec89", "#021c3d", "#3B5323", "#046b00", "#cef45a", "#421C52", "#FEA620" ] } ] }; var optionsPie = { responsive: true, scaleBeginAtZero: true, tooltips: { callbacks: { label: function (tooltipItem, data) { return data.labels[tooltipItem.index] + ": " + formatter.format(data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]); } } } }; var ctx = $("#top10ItemsChart").get(0).getContext("2d"); var top10PieChart = new Chart(ctx, { type: 'pie', data: data, options: optionsPie }); $("#top10Legend").html(top10PieChart.generateLegend()); 

Do I need to add an afterDraw () event, and if so, how should I look for this to accomplish this?

UPDATE

I tried adding the onAnimationComplete () callback to the chart constructor:

 var top10PieChart = new Chart(ctx, { type: 'pie', data: data, options: optionsPie, onAnimationComplete: function () { var ctx = this.chart.ctx; ctx.font = this.scale.font; ctx.fillStyle = this.scale.textColor; ctx.textAlign = "center"; ctx.textBaseline = "center"; this.datasets.forEach(function(dataset) { dataset.points.forEach(function(points) { ctx.fillText(points.value, points.x, points.y - 10); }); }); } }); 

... but he does nothing.

UPDATE 2

I also tried adding the following to the options object:

 , tooltipTemplate: "<%= value %>", onAnimationComplete: function () { this.showTooltip(this.datasets[0].bars, true); } 

... with the same results (no change).

UPDATE 3

Ok, I was hoping the answer here would work, and in the end this new code for my pie chart is based on the answer:

Added to the Pie option:

 showTooltips: false, onAnimationProgress: drawSegmentValues 

Added after link to item:

 var midX = canvas.width / 2; var midY = canvas.height / 2 

Added after creating the pie chart instance:

 var radius = top10PieChart.outerRadius; 

Added drawSegmentValues ​​() function

In context (pun intended):

  // Top 10 Pie Chart var formatter = new Intl.NumberFormat("en-US"); var data = { labels: [ "Bananas (18%)", "Lettuce, Romaine (14%)", "Melons, Watermelon (10%)", "Pineapple (10%)", "Berries (10%)", "Lettuce, Spring Mix (9%)", "Broccoli (8%)", "Melons, Honeydew (7%)", "Grapes (7%)", "Melons, Cantaloupe (7%)" ], datasets: [ { data: [2755, 2256, 1637, 1608, 1603, 1433, 1207, 1076 1056, 1048], backgroundColor: [ "#FFE135", "#3B5323", "#fc6c85", "#ffec89", "#021c3d", "#3B5323", "#046b00", "#cef45a", "#421C52", "#FEA620" ] } ] }; var optionsPie = { responsive: true, scaleBeginAtZero: true, legend: { display: false }, tooltips: { callbacks: { label: function (tooltipItem, data) { return data.labels[tooltipItem.index] + ": " + formatter.format data.datasets[tooltipItem.datasetIndex].data[ tooltipItem.index]); } } }, showTooltips: false, onAnimationProgress: drawSegmentValues }; var ctx = $("#top10ItemsChart").get(0).getContext("2d"); var midX = canvas.width / 2; var midY = canvas.height / 2 var top10PieChart = new Chart(ctx, { type: 'pie', data: data, options: optionsPie//, }); var radius = top10PieChart.outerRadius; $("#top10Legend").html(top10PieChart.generateLegend()); // </ Top 10 Pie Chart // Price Compliance Bar Chart . . . this horizontal bar chart code elided for brevity, bu unchanged from their working state // Forecast/Impact Analysis Bar chart . . . this horizontal bar chart code also elided for brevity, bu unchanged from their working state function drawSegmentValues() { for (var i = 0; i < top10PieChart.segments.length; i++) { ctx.fillStyle = "white"; var textSize = canvas.width / 10; ctx.font = textSize + "px Verdana"; // Get needed variables var value = top10PieChart.segments[i].value; var startAngle = top10PieChart.segments[i].startAngle; var endAngle = top10PieChart.segments[i].endAngle; var middleAngle = startAngle + ((endAngle - startAngle) 2); // Compute text location var posX = (radius / 2) * Math.cos(middleAngle) + midX; var posY = (radius / 2) * Math.sin(middleAngle) + midY; // Text offside by middle var w_offset = ctx.measureText(value).width / 2; var h_offset = textSize / 4; ctx.fillText(value, posX - w_offset, posY + h_offset); } } 

... but he completely closed all three charts without leaving anything visible / drawing.

UPDATE 4

By the way, I tried this answer, but without a result / change - it still displays the data about the hang, as provided, but nothing happens.

In addition, the associated script shows both the value and the percentage; due to restrictions on real estate, I want the percentage to be only “always on” - “the entire enchiladas” should be visible only with a pair.

0
javascript pie-chart drawing
Sep 22 '16 at 18:25
source share
2 answers

The following solution uses the same calculation as lamelemon's , but using Chart.js Plugins , which brings additional benefits :

  • This blink effect, caused by animation.onComplete , no longer occurs, as it occurs immediately, without waiting for the need.

  • Hint above text, which is more natural.

Runs a plugin that does this:

 Chart.pluginService.register({ afterDatasetsDraw: function(chartInstance) { // We get the canvas context var ctx = chartInstance.chart.ctx; // And set the properties we need ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily); ctx.textAlign = 'center'; ctx.textBaseline = 'bottom'; ctx.fillStyle = '#666'; // For ervery dataset ... chartInstance.config.data.datasets.forEach(function(dataset) { // For every data in the dataset ... for (var i = 0; i < dataset.data.length; i++) { // We get all the properties & values we need var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model, total = dataset._meta[Object.keys(dataset._meta)[0]].total, mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius) / 2, start_angle = model.startAngle, end_angle = model.endAngle, mid_angle = start_angle + (end_angle - start_angle) / 2; // We calculate the right positions for our text var x = mid_radius * 1.5 * Math.cos(mid_angle); var y = mid_radius * 1.5 * Math.sin(mid_angle); // We calculate the percentage var percent = String(Math.round(dataset.data[i] / total * 100)) + "%"; // And display it ctx.fillText(percent, model.x + x, model.y + y); } }); } }); 




You can check this plugin on on this jsFiddle , and here is the result:

enter image description here

+2
Sep 28 '16 at 9:34
source share

It looks good that you have simple syntax errors in the updated code that probably occurred with the copy. Ignoring this, you can control this by creating a function in the animation settings. Here is the fiddle . Thanks to Hong Tran's work here .

 animation: { duration: 0, easing: "easeOutQuart", onComplete: function () { var ctx = this.chart.ctx; ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily); ctx.textAlign = 'center'; ctx.textBaseline = 'bottom'; this.data.datasets.forEach(function (dataset) { for (var i = 0; i < dataset.data.length; i++) { var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model, total = dataset._meta[Object.keys(dataset._meta)[0]].total, mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius)/2, start_angle = model.startAngle, end_angle = model.endAngle, mid_angle = start_angle + (end_angle - start_angle)/2; var x = mid_radius * Math.cos(mid_angle); var y = mid_radius * Math.sin(mid_angle); ctx.fillStyle = '#fff'; if (i == 3){ // Darker text color for lighter background ctx.fillStyle = '#444'; } var percent = String(Math.round(dataset.data[i]/total*100)) + "%"; // this prints the data number ctx.fillText(dataset.data[i], model.x + x, model.y + y); // this prints the percentage ctx.fillText(percent, model.x + x, model.y + y + 15); } }); } } 
+1
Sep 23 '16 at 3:58
source share



All Articles