Câu trả lời:
Bạn phải sửa đổi mã như: in chart.Doughnut.defaults
labelFontFamily : "Arial",
labelFontStyle : "normal",
labelFontSize : 24,
labelFontColor : "#666"
và sau đó trong chức năng drawPieSegments
ctx.fillText(data[0].value + "%", width/2 - 20, width/2, 200);
Xem phần kéo này: https://github.com/nnnick/Chart.js/pull/35
đây là một http://jsfiddle.net/mayankcpdixit/6xV78/ cách triển khai tương tự.
Không có câu trả lời nào khác thay đổi kích thước văn bản dựa trên số lượng văn bản và kích thước của chiếc bánh rán. Đây là một tập lệnh nhỏ mà bạn có thể sử dụng để đặt động bất kỳ lượng văn bản nào vào giữa và nó sẽ tự động thay đổi kích thước.
Ví dụ: http://jsfiddle.net/kdvuxbtj/
Nó sẽ mất bất kỳ lượng văn bản nào trong chiếc bánh rán có kích thước hoàn hảo cho chiếc bánh rán. Để tránh chạm vào các cạnh, bạn có thể đặt phần đệm bên dưới dạng tỷ lệ phần trăm của đường kính bên trong hình tròn. Nếu bạn không đặt nó, nó sẽ mặc định là 20. Bạn cũng có màu, phông chữ và văn bản. Plugin sẽ lo phần còn lại.
Mã plugin sẽ bắt đầu với kích thước phông chữ cơ bản là 30px. Từ đó, nó sẽ kiểm tra chiều rộng của văn bản và so sánh nó với bán kính của hình tròn và thay đổi kích thước của nó dựa trên tỷ lệ hình tròn / chiều rộng văn bản.
Nó có kích thước phông chữ tối thiểu mặc định là 20px. Nếu văn bản vượt quá giới hạn ở kích thước phông chữ tối thiểu, nó sẽ bao bọc văn bản. Chiều cao dòng mặc định khi gói văn bản là 25px, nhưng bạn có thể thay đổi nó. Nếu bạn đặt kích thước phông chữ tối thiểu mặc định thành false, văn bản sẽ trở nên nhỏ vô hạn và không bao bọc.
Nó cũng có kích thước phông chữ tối đa mặc định là 75px trong trường hợp không có đủ văn bản và chữ sẽ quá lớn.
Đây là mã plugin
Chart.pluginService.register({
beforeDraw: function(chart) {
if (chart.config.options.elements.center) {
// Get ctx from string
var ctx = chart.chart.ctx;
// Get options from the center object in options
var centerConfig = chart.config.options.elements.center;
var fontStyle = centerConfig.fontStyle || 'Arial';
var txt = centerConfig.text;
var color = centerConfig.color || '#000';
var maxFontSize = centerConfig.maxFontSize || 75;
var sidePadding = centerConfig.sidePadding || 20;
var sidePaddingCalculated = (sidePadding / 100) * (chart.innerRadius * 2)
// Start with a base font of 30px
ctx.font = "30px " + fontStyle;
// Get the width of the string and also the width of the element minus 10 to give it 5px side padding
var stringWidth = ctx.measureText(txt).width;
var elementWidth = (chart.innerRadius * 2) - sidePaddingCalculated;
// Find out how much the font can grow in width.
var widthRatio = elementWidth / stringWidth;
var newFontSize = Math.floor(30 * widthRatio);
var elementHeight = (chart.innerRadius * 2);
// Pick a new font size so it will not be larger than the height of label.
var fontSizeToUse = Math.min(newFontSize, elementHeight, maxFontSize);
var minFontSize = centerConfig.minFontSize;
var lineHeight = centerConfig.lineHeight || 25;
var wrapText = false;
if (minFontSize === undefined) {
minFontSize = 20;
}
if (minFontSize && fontSizeToUse < minFontSize) {
fontSizeToUse = minFontSize;
wrapText = true;
}
// Set font settings to draw it correctly.
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
var centerX = ((chart.chartArea.left + chart.chartArea.right) / 2);
var centerY = ((chart.chartArea.top + chart.chartArea.bottom) / 2);
ctx.font = fontSizeToUse + "px " + fontStyle;
ctx.fillStyle = color;
if (!wrapText) {
ctx.fillText(txt, centerX, centerY);
return;
}
var words = txt.split(' ');
var line = '';
var lines = [];
// Break words up into multiple lines if necessary
for (var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = ctx.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > elementWidth && n > 0) {
lines.push(line);
line = words[n] + ' ';
} else {
line = testLine;
}
}
// Move the center up depending on line height and number of lines
centerY -= (lines.length / 2) * lineHeight;
for (var n = 0; n < lines.length; n++) {
ctx.fillText(lines[n], centerX, centerY);
centerY += lineHeight;
}
//Draw text in center
ctx.fillText(line, centerX, centerY);
}
}
});
Và bạn sử dụng các tùy chọn sau trong đối tượng biểu đồ của mình
options: {
elements: {
center: {
text: 'Red is 2/3 the total numbers',
color: '#FF6384', // Default is #000000
fontStyle: 'Arial', // Default is Arial
sidePadding: 20, // Default is 20 (as a percentage)
minFontSize: 20, // Default is 20 (in px), set to false and text will not wrap.
lineHeight: 25 // Default is 25 (in px), used for when text wraps
}
}
}
Ghi có cho @Jenna Sloan để được trợ giúp về phép toán được sử dụng trong giải pháp này.
Đây là ví dụ được dọn dẹp và kết hợp của các giải pháp trên - đáp ứng (cố gắng thay đổi kích thước cửa sổ), hỗ trợ hoạt ảnh tự căn chỉnh, hỗ trợ chú giải công cụ
https://jsfiddle.net/cmyker/u6rr5moq/
Chart.types.Doughnut.extend({
name: "DoughnutTextInside",
showTooltip: function() {
this.chart.ctx.save();
Chart.types.Doughnut.prototype.showTooltip.apply(this, arguments);
this.chart.ctx.restore();
},
draw: function() {
Chart.types.Doughnut.prototype.draw.apply(this, arguments);
var width = this.chart.width,
height = this.chart.height;
var fontSize = (height / 114).toFixed(2);
this.chart.ctx.font = fontSize + "em Verdana";
this.chart.ctx.textBaseline = "middle";
var text = "82%",
textX = Math.round((width - this.chart.ctx.measureText(text).width) / 2),
textY = height / 2;
this.chart.ctx.fillText(text, textX, textY);
}
});
var data = [{
value: 30,
color: "#F7464A"
}, {
value: 50,
color: "#E2EAE9"
}, {
value: 100,
color: "#D4CCC5"
}, {
value: 40,
color: "#949FB1"
}, {
value: 120,
color: "#4D5360"
}];
var DoughnutTextInsideChart = new Chart($('#myChart')[0].getContext('2d')).DoughnutTextInside(data, {
responsive: true
});
<html>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"></script>
<body>
<canvas id="myChart"></canvas>
</body>
</html>
CẬP NHẬT 17.06.16:
Chức năng tương tự nhưng cho chart.js phiên bản 2:
https://jsfiddle.net/cmyker/ooxdL2vj/
var data = {
labels: [
"Red",
"Blue",
"Yellow"
],
datasets: [
{
data: [300, 50, 100],
backgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
]
}]
};
Chart.pluginService.register({
beforeDraw: function(chart) {
var width = chart.chart.width,
height = chart.chart.height,
ctx = chart.chart.ctx;
ctx.restore();
var fontSize = (height / 114).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";
var text = "75%",
textX = Math.round((width - ctx.measureText(text).width) / 2),
textY = height / 2;
ctx.fillText(text, textX, textY);
ctx.save();
}
});
var chart = new Chart(document.getElementById('myChart'), {
type: 'doughnut',
data: data,
options: {
responsive: true,
legend: {
display: false
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.6/Chart.bundle.js"></script>
<canvas id="myChart"></canvas>
Uncaught TypeError: Cannot read property 'extend' of undefined
bất kỳ ý tưởng?
Tôi tránh sửa đổi mã chart.js để thực hiện điều này, vì nó khá dễ dàng với CSS và HTML thông thường. Đây là giải pháp của tôi:
HTML:
<canvas id="productChart1" width="170"></canvas>
<div class="donut-inner">
<h5>47 / 60 st</h5>
<span>(30 / 25 st)</span>
</div>
CSS:
.donut-inner {
margin-top: -100px;
margin-bottom: 100px;
}
.donut-inner h5 {
margin-bottom: 5px;
margin-top: 0;
}
.donut-inner span {
font-size: 12px;
}
Đầu ra trông như thế này:
Điều này cũng đang hoạt động ở cuối của tôi ...
<div style="width: 100px; height: 100px; float: left; position: relative;">
<div
style="width: 100%; height: 40px; position: absolute; top: 50%; left: 0; margin-top: -20px; line-height:19px; text-align: center; z-index: 999999999999999">
99%<Br />
Total
</div>
<canvas id="chart-area" width="100" height="100" />
</div>
Dựa trên câu trả lời @ rap-2-h, Đây là mã để sử dụng văn bản trên biểu đồ bánh rán trên Chart.js để sử dụng trong trang tổng quan như. Nó có kích thước phông chữ động cho tùy chọn đáp ứng.
HTML:
<div>text
<canvas id="chart-area" width="300" height="300" style="border:1px solid"/><div>
Kịch bản:
var doughnutData = [
{
value: 100,
color:"#F7464A",
highlight: "#FF5A5E",
label: "Red"
},
{
value: 50,
color: "#CCCCCC",
highlight: "#5AD3D1",
label: "Green"
}
];
$(document).ready(function(){
var ctx = $('#chart-area').get(0).getContext("2d");
var myDoughnut = new Chart(ctx).Doughnut(doughnutData,{
animation:true,
responsive: true,
showTooltips: false,
percentageInnerCutout : 70,
segmentShowStroke : false,
onAnimationComplete: function() {
var canvasWidthvar = $('#chart-area').width();
var canvasHeight = $('#chart-area').height();
//this constant base on canvasHeight / 2.8em
var constant = 114;
var fontsize = (canvasHeight/constant).toFixed(2);
ctx.font=fontsize +"em Verdana";
ctx.textBaseline="middle";
var total = 0;
$.each(doughnutData,function() {
total += parseInt(this.value,10);
});
var tpercentage = ((doughnutData[0].value/total)*100).toFixed(2)+"%";
var textWidth = ctx.measureText(tpercentage).width;
var txtPosx = Math.round((canvasWidthvar - textWidth)/2);
ctx.fillText(tpercentage, txtPosx, canvasHeight/2);
}
});
});
Đây là mã mẫu. Hãy thử thay đổi kích thước cửa sổ. http://jsbin.com/wapono/13/edit
Bạn có thể sử dụng css với định vị tương đối / tuyệt đối nếu bạn muốn nó đáp ứng. Thêm vào đó, nó có thể xử lý dễ dàng nhiều dòng.
https://jsfiddle.net/mgyp0jkk/
<div class="relative">
<canvas id="myChart"></canvas>
<div class="absolute-center text-center">
<p>Some text</p>
<p>Some text</p>
</div>
</div>
Điều này dựa trên bản cập nhật của Cmyker cho Chart.js 2. (được đăng dưới dạng một câu trả lời khác vì tôi chưa thể bình luận)
Tôi gặp sự cố với căn chỉnh văn bản trên Chrome khi chú giải được hiển thị vì chiều cao biểu đồ không bao gồm điều này nên nó không được căn chỉnh chính xác ở giữa. Đã sửa lỗi này bằng cách tính toán điều này trong phép tính fontSize và textY.
Tôi đã tính toán tỷ lệ phần trăm bên trong phương pháp chứ không phải một giá trị đặt vì tôi có nhiều giá trị này trên trang. Các giả định là biểu đồ của bạn chỉ có 2 giá trị (nếu không thì tỷ lệ phần trăm là bao nhiêu? Và giá trị đầu tiên là giá trị bạn muốn hiển thị phần trăm. Tôi cũng có rất nhiều biểu đồ khác nên tôi kiểm tra type = donut. Tôi chỉ sử dụng bánh rán để hiển thị tỷ lệ phần trăm để nó phù hợp với tôi.
Màu văn bản có vẻ hơi bị nhấn và bị thiếu tùy thuộc vào thứ tự mọi thứ chạy theo thứ tự nào, v.v. vì vậy tôi đã gặp phải vấn đề khi thay đổi kích thước rằng văn bản sẽ thay đổi màu sắc (giữa màu đen và màu chính trong một trường hợp và màu phụ và màu trắng trong một trường hợp khác) vì vậy Tôi "lưu" bất kỳ kiểu tô hiện có nào, vẽ văn bản (bằng màu của dữ liệu chính) sau đó khôi phục kiểu tô cũ. (Giữ nguyên kiểu tô cũ có vẻ không cần thiết nhưng bạn không bao giờ biết.)
https://jsfiddle.net/g733tj8h/
Chart.pluginService.register({
beforeDraw: function(chart) {
var width = chart.chart.width,
height = chart.chart.height,
ctx = chart.chart.ctx,
type = chart.config.type;
if (type == 'doughnut')
{
var percent = Math.round((chart.config.data.datasets[0].data[0] * 100) /
(chart.config.data.datasets[0].data[0] +
chart.config.data.datasets[0].data[1]));
var oldFill = ctx.fillStyle;
var fontSize = ((height - chart.chartArea.top) / 100).toFixed(2);
ctx.restore();
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle"
var text = percent + "%",
textX = Math.round((width - ctx.measureText(text).width) / 2),
textY = (height + chart.chartArea.top) / 2;
ctx.fillStyle = chart.config.data.datasets[0].backgroundColor[0];
ctx.fillText(text, textX, textY);
ctx.fillStyle = oldFill;
ctx.save();
}
}
});
Bạn cũng có thể dán mã của mayankcpdixit trong onAnimationComplete
tùy chọn:
// ...
var myDoughnutChart = new Chart(ctx).Doughnut(data, {
onAnimationComplete: function() {
ctx.fillText(data[0].value + "%", 100 - 20, 100, 200);
}
});
Văn bản sẽ được hiển thị sau hoạt ảnh
save
phương pháp
Tôi tạo bản demo với 7 jQueryUI Slider và ChartJs (với văn bản động bên trong)
Chart.types.Doughnut.extend({
name: "DoughnutTextInside",
showTooltip: function() {
this.chart.ctx.save();
Chart.types.Doughnut.prototype.showTooltip.apply(this, arguments);
this.chart.ctx.restore();
},
draw: function() {
Chart.types.Doughnut.prototype.draw.apply(this, arguments);
var width = this.chart.width,
height = this.chart.height;
var fontSize = (height / 140).toFixed(2);
this.chart.ctx.font = fontSize + "em Verdana";
this.chart.ctx.textBaseline = "middle";
var red = $( "#red" ).slider( "value" ),
green = $( "#green" ).slider( "value" ),
blue = $( "#blue" ).slider( "value" ),
yellow = $( "#yellow" ).slider( "value" ),
sienna = $( "#sienna" ).slider( "value" ),
gold = $( "#gold" ).slider( "value" ),
violet = $( "#violet" ).slider( "value" );
var text = (red+green+blue+yellow+sienna+gold+violet) + " minutes";
var textX = Math.round((width - this.chart.ctx.measureText(text).width) / 2);
var textY = height / 2;
this.chart.ctx.fillStyle = '#000000';
this.chart.ctx.fillText(text, textX, textY);
}
});
var ctx = $("#myChart").get(0).getContext("2d");
var myDoughnutChart = new Chart(ctx).DoughnutTextInside(data, {
responsive: false
});
Câu trả lời của @ rap-2-h và @Ztuons Ch không cho phép showTooltips
tùy chọn hoạt động, nhưng những gì bạn có thể làm là tạo và xếp lớp canvas
đối tượng thứ hai phía sau đối tượng hiển thị biểu đồ.
Phần quan trọng là kiểu dáng được yêu cầu trong các div và cho chính đối tượng canvas để chúng hiển thị chồng lên nhau.
var data = [
{value : 100, color : 'rgba(226,151,093,1)', highlight : 'rgba(226,151,093,0.75)', label : "Sector 1"},
{value : 100, color : 'rgba(214,113,088,1)', highlight : 'rgba(214,113,088,0.75)', label : "Sector 2"},
{value : 100, color : 'rgba(202,097,096,1)', highlight : 'rgba(202,097,096,0.75)', label : "Sector 3"}
]
var options = { showTooltips : true };
var total = 0;
for (i = 0; i < data.length; i++) {
total = total + data[i].value;
}
var chartCtx = $("#canvas").get(0).getContext("2d");
var chart = new Chart(chartCtx).Doughnut(data, options);
var textCtx = $("#text").get(0).getContext("2d");
textCtx.textAlign = "center";
textCtx.textBaseline = "middle";
textCtx.font = "30px sans-serif";
textCtx.fillText(total, 150, 150);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js"></script>
<html>
<body>
<div style="position: relative; width:300px; height:300px;">
<canvas id="text"
style="z-index: 1;
position: absolute;
left: 0px;
top: 0px;"
height="300"
width="300"></canvas>
<canvas id="canvas"
style="z-index: 2;
position: absolute;
left: 0px;
top: 0px;"
height="300"
width="300"></canvas>
</div>
</body>
</html>
Đây là jsfiddle: https://jsfiddle.net/68vxqyak/1/
@Cmyker, giải pháp tuyệt vời cho chart.js v2
Một chút cải tiến: Nên kiểm tra id canvas phù hợp, hãy xem đoạn mã đã sửa đổi bên dưới. Nếu không, văn bản (tức là 75%) cũng được hiển thị ở giữa các loại biểu đồ khác trong trang.
Chart.pluginService.register({
beforeDraw: function(chart) {
if (chart.canvas.id === 'doghnutChart') {
let width = chart.chart.width,
height = chart.chart.outerRadius * 2,
ctx = chart.chart.ctx;
rewardImg.width = 40;
rewardImg.height = 40;
let imageX = Math.round((width - rewardImg.width) / 2),
imageY = (height - rewardImg.height ) / 2;
ctx.drawImage(rewardImg, imageX, imageY, 40, 40);
ctx.save();
}
}
});
Vì chú giải (xem: http://www.chartjs.org/docs/latest/configuration/legend.html ) phóng đại chiều cao biểu đồ, nên giá trị cho chiều cao sẽ được tính bằng bán kính.
Trước hết, xin chúc mừng khi chọn Chart.js! Tôi đang sử dụng nó cho một trong những dự án hiện tại của mình và tôi hoàn toàn thích nó - nó thực hiện công việc một cách hoàn hảo.
Mặc dù nhãn / chú giải công cụ chưa phải là một phần của thư viện, bạn có thể muốn xem ba yêu cầu kéo sau:
Và, như Cracker0dks đã đề cập, Chart.js sử dụng canvas
để hiển thị, vì vậy bạn cũng có thể triển khai các chú giải công cụ của riêng mình bằng cách tương tác trực tiếp với nó.
Hi vọng điêu nay co ich.
Nói chung, giải pháp của Alesana hoạt động rất tốt đối với tôi, nhưng giống như những giải pháp khác, tôi muốn có thể chỉ định nơi xảy ra ngắt dòng. Tôi đã thực hiện một số sửa đổi đơn giản để bọc các dòng ở ký tự '\ n', miễn là văn bản đã được bao bọc. Một giải pháp hoàn chỉnh hơn sẽ buộc phải gói nếu có bất kỳ ký tự '\ n' nào trong văn bản, nhưng tôi không có thời gian để làm điều đó hoạt động với định cỡ phông chữ. Sự thay đổi cũng căn giữa tốt hơn một chút theo chiều ngang khi gói (tránh khoảng trống ở cuối). Đoạn mã bên dưới (Tôi chưa thể đăng nhận xét).
Sẽ thật tuyệt nếu ai đó đưa plugin này lên GitHub ...
Chart.pluginService.register({
beforeDraw: function(chart) {
if (chart.config.options.elements.center) {
// Get ctx from string
var ctx = chart.chart.ctx;
// Get options from the center object in options
var centerConfig = chart.config.options.elements.center;
var fontStyle = centerConfig.fontStyle || 'Arial';
var txt = centerConfig.text;
var color = centerConfig.color || '#000';
var maxFontSize = centerConfig.maxFontSize || 75;
var sidePadding = centerConfig.sidePadding || 20;
var sidePaddingCalculated = (sidePadding / 100) * (chart.innerRadius * 2)
// Start with a base font of 30px
ctx.font = "30px " + fontStyle;
// Get the width of the string and also the width of the element minus 10 to give it 5px side padding
var stringWidth = ctx.measureText(txt).width;
var elementWidth = (chart.innerRadius * 2) - sidePaddingCalculated;
// Find out how much the font can grow in width.
var widthRatio = elementWidth / stringWidth;
var newFontSize = Math.floor(30 * widthRatio);
var elementHeight = (chart.innerRadius * 2);
// Pick a new font size so it will not be larger than the height of label.
var fontSizeToUse = Math.min(newFontSize, elementHeight, maxFontSize);
var minFontSize = centerConfig.minFontSize;
var lineHeight = centerConfig.lineHeight || 25;
var wrapText = false;
if (minFontSize === undefined) {
minFontSize = 20;
}
if (minFontSize && fontSizeToUse < minFontSize) {
fontSizeToUse = minFontSize;
wrapText = true;
}
// Set font settings to draw it correctly.
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
var centerX = ((chart.chartArea.left + chart.chartArea.right) / 2);
var centerY = ((chart.chartArea.top + chart.chartArea.bottom) / 2);
ctx.font = fontSizeToUse + "px " + fontStyle;
ctx.fillStyle = color;
if (!wrapText) {
ctx.fillText(txt, centerX, centerY);
return;
}
var lines = [];
var chunks = txt.split('\n');
for (var m = 0; m < chunks.length; m++) {
var words = chunks[m].split(' ');
var line;
// Break words up into multiple lines if necessary
for (var n = 0; n < words.length; n++) {
var testLine = (n == 0) ? words[n] : line + ' ' + words[n];
var metrics = ctx.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > elementWidth && n > 0) {
lines.push(line);
line = words[n];
} else {
line = testLine;
}
}
lines.push(line);
}
// Move the center up depending on line height and number of lines
centerY -= ((lines.length-1) / 2) * lineHeight;
// All but last line
for (var n = 0; n < lines.length; n++) {
ctx.fillText(lines[n], centerX, centerY);
centerY += lineHeight;
}
}
}
});