답변:
다음과 같이 코드를 수정해야합니다. chart.Doughnut.defaults
labelFontFamily : "Arial",
labelFontStyle : "normal",
labelFontSize : 24,
labelFontColor : "#666"
그리고 기능 drawPieSegments
ctx.fillText(data[0].value + "%", width/2 - 20, width/2, 200);
이 풀을 참조하십시오 : https://github.com/nnnick/Chart.js/pull/35
여기 에 같은 것을 구현 하는 바이올린 http://jsfiddle.net/mayankcpdixit/6xV78/이 있습니다.
다른 답변은 텍스트 양과 도넛 크기에 따라 텍스트 크기를 조정하지 않습니다. 다음은 중간에 임의의 양의 텍스트를 동적으로 배치하는 데 사용할 수있는 작은 스크립트이며 자동으로 크기가 조정됩니다.
예 : http://jsfiddle.net/kdvuxbtj/
도넛에 딱 맞는 크기의 도넛에 텍스트 양이 필요합니다. 가장자리에 닿지 않도록 원 안쪽 지름의 백분율로 측면 패딩을 설정할 수 있습니다. 설정하지 않으면 기본값은 20입니다. 색상, 글꼴 및 텍스트도 있습니다. 플러그인이 나머지를 처리합니다.
플러그인 코드는 30px의 기본 글꼴 크기로 시작합니다. 거기에서 텍스트의 너비를 확인하고 원의 반경과 비교하고 원 / 텍스트 너비 비율에 따라 크기를 조정합니다.
기본 최소 글꼴 크기는 20px입니다. 텍스트가 최소 글꼴 크기에서 경계를 초과하면 텍스트를 래핑합니다. 텍스트 줄 바꿈시 기본 줄 높이는 25px이지만 변경할 수 있습니다. 기본 최소 글꼴 크기를 false로 설정하면 텍스트가 무한히 작아지고 줄 바꿈되지 않습니다.
또한 텍스트가 충분하지 않고 글자가 너무 큰 경우 기본 최대 글꼴 크기는 75px입니다.
이것은 플러그인 코드입니다
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);
}
}
});
그리고 차트 개체에서 다음 옵션을 사용합니다.
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
}
}
}
이 솔루션에 사용 된 수학에 도움 을 주신 @Jenna Sloan 에게 감사드립니다 .
다음은 위 솔루션의 정리 및 결합 된 예입니다. 반응 형 (창 크기 조정 시도), 애니메이션 자체 정렬 지원, 툴팁 지원
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>
업데이트 17.06.16 :
동일한 기능이지만 chart.js 버전 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
어떤 아이디어를 얻었 습니까?
이것을 달성하기 위해 chart.js 코드를 수정하는 것을 피할 것입니다. 일반 CSS와 HTML을 사용하면 매우 쉽기 때문입니다. 내 해결책은 다음과 같습니다.
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;
}
출력은 다음과 같습니다.
이것은 또한 내 끝에서 작동합니다 ...
<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>
@ rap-2-h 답변을 기반으로 대시 보드에서 사용하기 위해 Chart.js의 도넛 차트에 텍스트를 사용하는 코드가 있습니다. 반응 형 옵션에 대한 동적 글꼴 크기가 있습니다.
HTML :
<div>text
<canvas id="chart-area" width="300" height="300" style="border:1px solid"/><div>
스크립트:
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);
}
});
});
여기 샘플 code.try 창 크기를 조정하십시오. http://jsbin.com/wapono/13/edit
반응을 원하면 상대 / 절대 위치와 함께 CSS를 사용할 수 있습니다. 또한 여러 줄을 쉽게 처리 할 수 있습니다.
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>
이것은 Chart.js 2에 대한 Cmyker의 업데이트를 기반으로합니다. (아직 댓글을 달 수 없으므로 다른 답변으로 게시 됨)
차트 높이에 이것을 포함하지 않아서 중간에 올바르게 정렬되지 않았기 때문에 범례가 표시 될 때 Chrome에서 텍스트 정렬에 문제가있었습니다. fontSize 및 textY 계산에서이를 고려하여이 문제를 해결했습니다.
페이지에 여러 개가 있으므로 설정된 값이 아닌 메서드 내부에서 백분율을 계산했습니다. 차트에는 2 개의 값만 있다고 가정합니다 (그렇지 않으면 백분율은 무엇입니까? 첫 번째는 백분율을 표시하려는 차트입니다. 다른 차트도 여러 개 있으므로 유형 = 도넛을 확인합니다. 나는 도넛을 사용하여 백분율을 표시하기 때문에 나를 위해 작동합니다.
텍스트 색상은 어떤 순서로 실행되는지 등에 따라 약간 맞고 놓치는 것처럼 보이므로 크기를 조정할 때 텍스트 색상이 변경되는 문제가 발생했습니다 (한 경우에는 검은 색과 기본 색상, 다른 경우에는 보조 색상과 흰색). 기존 채우기 스타일이 무엇이든 "저장"하고 텍스트 (기본 데이터 색상)를 그린 다음 이전 채우기 스타일을 복원합니다. (이전 채우기 스타일을 유지하는 것은 필요하지 않은 것 같지만 알 수 없습니다.)
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();
}
}
});
onAnimationComplete
옵션에 mayankcpdixit의 코드를 붙여 넣을 수도 있습니다.
// ...
var myDoughnutChart = new Chart(ctx).Doughnut(data, {
onAnimationComplete: function() {
ctx.fillText(data[0].value + "%", 100 - 20, 100, 200);
}
});
애니메이션 후 텍스트가 표시됩니다.
save
있어서
7 개의 jQueryUI Slider 및 ChartJ (동적 텍스트 포함)로 데모를 만듭니다.
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
});
@ rap-2-h 및 @Ztuons Ch의 대답은 showTooltips
옵션을 활성화 하는 것을 허용하지 않지만 canvas
차트를 렌더링하는 개체 뒤에 두 번째 개체를 만들고 레이어를 만드는 것입니다 .
중요한 부분은 div와 캔버스 객체 자체에 필요한 스타일링으로 서로 위에 렌더링되도록하는 것입니다.
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>
jsfiddle은 다음과 같습니다 : https://jsfiddle.net/68vxqyak/1/
@Cmyker, chart.js v2를위한 훌륭한 솔루션
약간의 개선 사항 : 적절한 캔버스 ID를 확인하는 것이 좋습니다. 아래 수정 된 스 니펫을 참조하세요. 그렇지 않으면 텍스트 (예 : 75 %)도 페이지 내의 다른 차트 유형 중간에 렌더링됩니다.
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();
}
}
});
범례 ( http://www.chartjs.org/docs/latest/configuration/legend.html 참조 )는 차트 높이를 확대하므로 높이 값은 반경으로 구해야합니다.
우선, Chart.js 선택에 대한 찬사! 현재 프로젝트 중 하나에서 사용하고 있으며 정말 마음에 듭니다. 완벽하게 작동합니다.
레이블 / 툴팁은 아직 라이브러리의 일부가 아니지만 다음 세 가지 풀 요청을 살펴볼 수 있습니다.
그리고 Cracker0dks가 언급했듯이 Chart.js는canvas
렌더링에 하므로 직접 상호 작용하여 자신의 툴팁을 구현할 수도 있습니다.
도움이 되었기를 바랍니다.
Alesana의 솔루션은 일반적으로 저에게 매우 잘 작동하지만 다른 사람들과 마찬가지로 줄 바꿈이 발생하는 위치를 지정할 수 있기를 원했습니다. 텍스트가 이미 줄 바꿈되어있는 한 '\ n'문자로 줄 바꿈하기 위해 몇 가지 간단한 수정을했습니다 . 더 완벽한 솔루션은 텍스트에 '\ 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;
}
}
}
});