Я использую Chart.js для построения круговой диаграммы на моей php-странице. Я нашел всплывающую подсказку, показывающую значения каждого кусочка.
Но я хочу отобразить эти значения, как показано ниже.
Я не знаю, как это сделать с помощью chart.js.
Пожалуйста, помогите мне.
Мой код Javascript:
function drawPie(canvasId,data,legend){
var ctx = $("#pie-canvas-" + canvasId).get(0).getContext("2d");
var piedata = [];
$.each(data,function(i,val){
piedata.push({value:val.count,color:val.color,label:val.status});
});
var options =
{
tooltipTemplate: "<%= Math.round(circumference / 6.283 * 100) %>%",
}
var pie = new Chart(ctx).Pie(piedata,options);
if(legend)document.getElementById("legend").innerHTML = pie.generateLegend();
}
php код:
printf('<table><tr>');
echo '<td style="text-align: right;"><canvas id="pie-canvas-'
. $canvasId
. '" width="256" height="256" ></canvas></td><td style="text-align: left;width:360px;height:auto" id="legend" class="chart-legend"></td></tr></table>';
echo '<script type="text/javascript">drawPie('
. $canvasId
. ', '
. $data3
.', '
. $legend
. ');</script>';
Для Chart.js 2.0 и выше данные объекта Chart изменились. Для тех, кто использует Chart.js 2.0+, ниже приведен пример использования метода HTML5 Canvas fillText()
для отображения значения данных внутри кругового среза. Код работает и для пончиковой диаграммы, с единственной разницей: type: 'pie'
против type: 'doughnut'
при создании диаграммы.
Сценарий:
Javascript
var data = {
datasets: [{
data: [
11,
16,
7,
3,
14
],
backgroundColor: [
"#FF6384",
"#4BC0C0",
"#FFCE56",
"#E7E9ED",
"#36A2EB"
],
label: 'My dataset' // for legend
}],
labels: [
"Red",
"Green",
"Yellow",
"Grey",
"Blue"
]
};
var pieOptions = {
events: false,
animation: {
duration: 500,
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)) + "%";
//Don't Display If Legend is hide or value is 0
if(dataset.data[i] != 0 && dataset._meta[0].data[i].hidden != true) {
ctx.fillText(dataset.data[i], model.x + x, model.y + y);
// Display percent in another line, line break doesn't work for fillText
ctx.fillText(percent, model.x + x, model.y + y + 15);
}
}
});
}
}
};
var pieChartCanvas = $("#pieChart");
var pieChart = new Chart(pieChartCanvas, {
type: 'pie', // or doughnut
data: data,
options: pieOptions
});
HTML
<canvas id="pieChart" width=200 height=200></canvas>
[jsFiddle][1]
Из того, что я знаю, я не верю, что в Chart.JS есть какая-либо функциональность для рисования текста на круговой диаграмме. Но это не значит, что вы не можете сделать это самостоятельно на родном JavaScript. Я приведу пример, как это сделать, ниже приведен код для рисования текста для каждого сегмента круговой диаграммы:
function drawSegmentValues()
{
for(var i=0; i<myPieChart.segments.length; i++)
{
// Default properties for text (size is scaled)
ctx.fillStyle="white";
var textSize = canvas.width/10;
ctx.font= textSize+"px Verdana";
// Get needed variables
var value = myPieChart.segments[i].value;
var startAngle = myPieChart.segments[i].startAngle;
var endAngle = myPieChart.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 to middle of text
var w_offset = ctx.measureText(value).width/2;
var h_offset = textSize/4;
ctx.fillText(value, posX - w_offset, posY + h_offset);
}
}
Круговая диаграмма имеет массив сегментов, хранящихся в PieChart.segments
, мы можем посмотреть на startAngle
и endAngle
этих сегментов, чтобы определить угол между ними, где текст будет middleAngle
. Затем мы переместимся в этом направлении на Radius/2
, чтобы оказаться в средней точке графика в радианах.
В приведенном выше примере выполняются некоторые другие операции по очистке, поскольку положение текста, нарисованного в fillText()
, находится в правом верхнем углу, нам нужно получить некоторые значения смещения, чтобы исправить это. И, наконец, textSize
определяется на основе размера самого графика, чем больше график, тем больше текст.
[Пример скрипки](
)С помощью небольшой модификации вы можете изменить значения дискретных чисел для набора данных в процентильные числа на графике. Для этого получите общее значение
элементов в вашем наборе данных, назовите это totalValue
. Затем для каждого сегмента вы можете найти процент, выполнив следующие действия:
Math.round(myPieChart.segments[i].value/totalValue*100)+'%';
Секция myPieChart.segments[i].value/totalValue
вычисляет процент, который сегмент занимает на графике. Например, если текущий сегмент имеет значение 50
, а totalValue равно 200
. Тогда процент, который занимает сегмент, будет таким: 50/200 => 0.25
. Остальное - для того, чтобы это выглядело красиво. 0.25*100 => 25
, затем мы добавляем %
в конце. Для плиток с целыми процентами я округляю до ближайшего целого числа, хотя это может привести к проблемам с точностью. Если нам нужна большая точность, можно использовать .toFixed(n)
для сохранения десятичных знаков. Например, для сохранения одного десятичного знака при необходимости мы можем сделать следующее:
var value = myPieChart.segments[i].value/totalValue*100;
if(Math.round(value) !== value)
value = (myPieChart.segments[i].value/totalValue*100).toFixed(1);
value = value + '%';
[Пример вычисления процентов с десятичными дробями](
2/)[Пример процентиля с целыми числами](
1/)Ответ @Hung Tran'работает идеально. В качестве улучшения я бы предложил не показывать значения, равные 0. Скажем, у вас есть 5 элементов, 2 из которых равны 0, а остальные имеют значения, решение выше покажет 0 и 0%. Лучше отфильтровать это с помощью проверки на неравенство 0!
var val = dataset.data[i]; var percent = String(Math.round(val/total*100)) + "%";
if(val != 0) { ctx.fillText(dataset.data[i], model.x + x, model.y + y); // Отображение процентов в другой строке, перенос строки не работает для fillText ctx.fillText(percent, model.x + x, model.y + y + 15); }
Обновленный код приведен ниже:
var data = {
datasets: [{
data: [
11,
16,
7,
3,
14
],
backgroundColor: [
"#FF6384",
"#4BC0C0",
"#FFCE56",
"#E7E9ED",
"#36A2EB"
],
label: 'My dataset' // for legend
}],
labels: [
"Red",
"Green",
"Yellow",
"Grey",
"Blue"
]
};
var pieOptions = {
events: false,
animation: {
duration: 500,
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 val = dataset.data[i];
var percent = String(Math.round(val/total*100)) + "%";
if(val != 0) {
ctx.fillText(dataset.data[i], model.x + x, model.y + y);
// Display percent in another line, line break doesn't work for fillText
ctx.fillText(percent, model.x + x, model.y + y + 15);
}
}
});
}
}
};
var pieChartCanvas = $("#pieChart");
var pieChart = new Chart(pieChartCanvas, {
type: 'pie', // or doughnut
data: data,
options: pieOptions
});