gpt4 book ai didi

javascript - 如何计算一个值并将其放置在 Chart.JS 条形图中的最后一个条形内?

转载 作者:行者123 更新时间:2023-11-28 05:29:59 28 4
gpt4 key购买 nike

由于在条形图上的最后一个条形上方放置标签似乎不可能或非常困难(没有有效的答案 here ),我现在想知道如何在最后一个条形内部放置标签。

我使用以下代码向水平条形图的所有条形添加标签:

Chart.pluginService.register({
afterDraw: function (chartInstance) {
if (chartInstance.id !== 1) return; // affect this one only
var ctx = chartInstance.chart.ctx;
// render the value of the chart above the bar
ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';

chartInstance.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;
ctx.fillText(dataset.data[i] + (Number.isInteger(dataset.data[i]) ? ".0" : "") + "%", ((model.x + model.base) / 2), model.y + (model.height / 3));
}
});
}
});

该工作图表如下所示:

enter image description here

...但这是一个“常规”(垂直)条形图,我尝试向最后一个条形图添加标签,如下所示:

Chart.pluginService.register({
afterDraw: function (chartInstance) {
if (chartInstance.id !== 2) return; // affect this one only
var ctx = chartInstance.chart.ctx;
// render the value of the chart above the bar
ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'center';

var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
ctx.fillText(dataset.data[dataset.data.length - 1]);
}
});

...失败(没有显示任何内容,事实上,它不仅会导致其自身的外观出现问题,还会导致页面上其他图表的外观出现问题,即使我使用代码仅将此事件应用于此特定图表:

enter image description here

那么如何计算一个值(基于最后一个和倒数第二个柱值),然后将计算出的“标签”放置在 Chart.JS 条形图中的最后一个柱内?

使用上面尝试的代码,我现在只想获取条形图内条形图的原始值;计算部分的逻辑可以留到后面。

一种可能是使其成为堆叠条形图,除了最后一个条形之外,没有向任何条形添加任何内容,然后将其背景颜色设置为白色以与图表背景融为一体...

更新

我尝试了我的最后一个想法;我想也许我可以通过将图表转变为堆叠条形图(从简单的条形图),添加第二组主要为“零”的数据作为堆栈的第二部分来实现我想要的目标,如下所示:

旧代码摘录:

var forecastChartData = {
labels: [
"Total Sales"
],
datasets: [
{
label: "8/28/2016 - 9/3/2016",
backgroundColor: "rgba(255,0,0,0.75)",
hoverBackgroundColor: "rgba(255,0,0,1)",
data: [240]
},
{
label: "9/4/2016 - 9/10/2016",
backgroundColor: "rgba(255,153,0,0.75)",
hoverBackgroundColor: "rgba(255,153,0,1)",
data: [272]
},
{
label: "9/11/2016 - 9/17/2016",
backgroundColor: "rgba(255,255,0,0.75)",
hoverBackgroundColor: "rgba(255,255,0,1)",
data: [250]
},
{
label: "9/18/2016 - 9/24/2016",
backgroundColor: "rgba(0,255,0,0.75)",
hoverBackgroundColor: "rgba(0,255,0,1)",
data: [232]
},
{
label: "9/25/2016 - 10/1/2016",
backgroundColor: "rgba(0,0,255,0.75)",
hoverBackgroundColor: "rgba(0,0,255,1)",
data: [244]
}],
};

var forecastOptions = {
tooltips: {
enabled: true
}
};

新代码:

var forecastChartData = {
labels: [
"Total Sales"
],
datasets: [
{
label: "8/28/2016 - 9/3/2016",
backgroundColor: "rgba(255,0,0,0.75)",
hoverBackgroundColor: "rgba(255,0,0,1)",
data: [240]
},
{
label: "9/4/2016 - 9/10/2016",
backgroundColor: "rgba(255,153,0,0.75)",
hoverBackgroundColor: "rgba(255,153,0,1)",
data: [272]
},
{
label: "9/11/2016 - 9/17/2016",
backgroundColor: "rgba(255,255,0,0.75)",
hoverBackgroundColor: "rgba(255,255,0,1)",
data: [250]
},
{
label: "9/18/2016 - 9/24/2016",
backgroundColor: "rgba(0,255,0,0.75)",
hoverBackgroundColor: "rgba(0,255,0,1)",
data: [232]
},
{
label: "9/25/2016 - 10/1/2016",
backgroundColor: "rgba(0,0,255,0.75)",
hoverBackgroundColor: "rgba(0,0,255,1)",
data: [244]
}],
[{
backgroundColor: "rgba(255, 255, 255, 0.5)",
hoverBackgroundColor: "rgba(200, 200, 200, 1)",
data: [0, 0, 0, 0, 5.2]
}]
};

var forecastOptions = {
scales: {
xAxes: [
{
stacked: true
}
],
yAxes: [
{
stacked: true
}
]
},
tooltips: {
enabled: true
}
};

但这根本没有帮助;我究竟做错了什么;如果一切正常,在使用我的新代码追求核选项后我该如何继续?

更新2

来自 Hung Tran 的代码 here让我靠近。我现在的选择是:

var forecastOptions = {
tooltips: {
enabled: true
},
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,
scale_max = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
ctx.fillStyle = '#444';
var y_pos = model.y - 5;
// Make sure data value does not get overflown and hidden
// when the bar's value is too close to max value of scale
// Note: The y value is reverse, it counts from top down
if ((scale_max - model.y) / scale_max >= 0.93)
y_pos = model.y + 20;
ctx.fillText(dataset.data[i], model.x, y_pos);
}
});
}
}
};

...它将数据值放置在每个条形上方。

如上所述,这很接近我想要的;不过,我真正想要的是最后一个值和当前值之间的差异。例如,使用此图表:

enter image description here

...我想看到的是:

240、272 (30)、250 (-22)、232 (-18)、244 (12)

或者可能只是最后一个柱上方的值,“244 (12)”或“12”。

这就是他们所说的他们想要的(后者),但如果他们改变主意并想要所有的值/差异,我不会感到惊讶。

更新3

该解决方案没有在条形顶部添加任何值,而是吃了我的一 block 馅饼:

enter image description here

更新4

这里几乎是 Index.cshtml 中的全部代码:

    <style>

.pieLegend li span {
display: inline-block;
width: 12px;
height: 12px;
margin-right: 5px;
}

#piechartlegendleft {
height: 360px;
width: 100%;
}

#top10Legend {
display: inline-block;
}

#top10Legend > ul {
list-style: none;
}

#container {
display: inline-block;
height: 50%;
width: 50%;
}
</style>
<script>
$(document).ready(function () {
$("body").on("click", "#btnGetData",
. . .
});

Chart.defaults.global.defaultFontFamily = "Candara";
Chart.defaults.global.defaultFontSize = 16;

// Top 10 Pie Chart
var formatter = new Intl.NumberFormat("en-US");

Chart.pluginService.register({
afterDatasetsDraw: function (chartInstance) {
var ctx = chartInstance.chart.ctx;

ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillStyle = '#666';

chartInstance.config.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 * 1.5 * Math.cos(mid_angle);
var y = mid_radius * 1.5 * Math.sin(mid_angle);

ctx.fillStyle = '#fff';
if (i === 0 || i === 3 || i === 7 || i === 9) { // Darker text color for lighter background
ctx.fillStyle = '#000';
}
var percent = String(Math.round(dataset.data[i] / total * 100)) + "%";
// this prints the data number
// this prints the percentage
ctx.fillText(percent, model.x + x, model.y + y);
}
});
}
});

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]);
}
}
},
};

var ctx = $("#top10ItemsChart").get(0).getContext("2d");
var top10PieChart = new Chart(ctx,
{
type: 'pie',
data: data,
options: optionsPie
});

$("#top10Legend").html(top10PieChart.generateLegend());
// </ Top 10 Pie Chart

// Price Compliance Bar Chart
Chart.pluginService.register({
afterDraw: function (chartInstance) {
if (chartInstance.id !== 1) return; // affect this one only
var ctx = chartInstance.chart.ctx;
// render the value of the chart above the bar
ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';

ctx.fillStyle = "#000";

chartInstance.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;
ctx.fillText(dataset.data[i] + (Number.isInteger(dataset.data[i]) ? ".0" : "") + "%", ((model.x + model.base) / 2), model.y + (model.height / 3));
}
});
}
});

var ctxBarChart = $("#priceComplianceBarChart").get(0).getContext("2d");
var priceComplianceData = {
labels: [
"Bix Produce", "Capitol City", "Charlies Portland", "Costa Fruit and Produce",
"Get Fresh Sales", "Loffredo East", "Loffredo West", "Paragon", "Piazza Produce"
],
datasets: [
{
label: "Price Compliant",
backgroundColor: "rgba(34,139,34,0.5)",
hoverBackgroundColor: "rgba(34,139,34,1)",
data: [99.0, 99.2, 99.4, 98.9, 99.1, 99.5, 99.6, 99.2, 99.7]
},
{
label: "Non-Compliant",
backgroundColor: "rgba(255, 0, 0, 0.5)",
hoverBackgroundColor: "rgba(255, 0, 0, 1)",
data: [1.0, 0.8, 0.6, 1.1, 0.9, 0.5, 0.4, 0.8, 0.3]
}
]
}

var priceComplianceOptions = {
scales: {
xAxes: [
{
stacked: true
}],
yAxes: [
{
stacked: true
}]
},
tooltips: {
enabled: false
}
};

var priceBarChart = new Chart(ctxBarChart,
{
type: 'horizontalBar',
data: priceComplianceData,
options: priceComplianceOptions
});
// </Price Compliance Bar Chart

// Forecast/Impact Analysis chart
var ctxForecastChart = $("#forecastLineChart"); //.get(0).getContext("2d");
// See if the "olde style" makes any diff (used by the Chart.JS Whisperer)
//var ctxForecastChart = document.getElementById("forecastLineChart"); // no diff

var forecastChartData = {
labels: ["Total Sales"],
datasets: [
{
label: "8/28/2016 - 9/3/2016",
backgroundColor: "rgba(255,0,0,0.75)",
hoverBackgroundColor: "rgba(255,0,0,1)",
data: [240]
},
{
label: "9/4/2016 - 9/10/2016",
backgroundColor: "rgba(255,153,0,0.75)",
hoverBackgroundColor: "rgba(255,153,0,1)",
data: [272]
},
{
label: "9/11/2016 - 9/17/2016",
backgroundColor: "rgba(255,255,0,0.75)",
hoverBackgroundColor: "rgba(255,255,0,1)",
data: [250]
},
{
label: "9/18/2016 - 9/24/2016",
backgroundColor: "rgba(0,255,0,0.75)",
hoverBackgroundColor: "rgba(0,255,0,1)",
data: [232]
},
{
label: "9/25/2016 - 10/1/2016",
backgroundColor: "rgba(0,0,255,0.75)",
hoverBackgroundColor: "rgba(0,0,255,1)",
data: [244]
}]
};

var forecastOptions = {
tooltips: {
enabled: true
},
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,
scale_max = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
ctx.fillStyle = '#444';
var y_pos = model.y - 5;
// Make sure data value does not get overflown and hidden
// when the bar's value is too close to max value of scale
// Note: The y value is reverse, it counts from top down
if ((scale_max - model.y) / scale_max >= 0.93)
y_pos = model.y + 20;
ctx.fillText(dataset.data[i], model.x, y_pos);
}
});
}
}
};

var forecastBarChart = new Chart(ctxForecastChart, {
type: 'bar',
//type: 'line',
data: forecastChartData,
options: forecastOptions
});
// </ Forecast/Impact Analysis chart

$('#delperfTable').DataTable({
"paging": false,
"info": false,
"searching": false
});
});


</script>
</head>

<body>
<div class="container body-content">
<div class="jumbotronjr">
<div class="col-md-3" style="margin-top: 0.6cm">
<img src="http://www.proactusa.com/wp-content/themes/proact/images/pa_logo_notag.png" height="86" width="133" alt="PRO*ACT usa logo">
</div>
<div class="col-md-9">
<label class="titletext" style="margin-top: 0.2cm;">Customer Dashboard</label>
<br />
<label class="titletextjr" style="margin-top: -2.2cm;" id="unitName">SODEXO</label>
<label class="cccsfont"> for the week of September 25 </label>
<input class="smalldatepicker" type="date" id="datepickerFrom" value="2016-09-25">
</input>
<label class="cccsfont"> to </label>
<input type="date" class="smalldatepicker" id="datepickerTo" value="2016-10-01">
</input>
<span id="newhourglass" class="fa fa-4x fa-refresh fa-spin boxRefresh hide" runat="server"></span>
<button class="btn btn-success btn-sm green" id="btnGetData"><span class="glyphicon glyphicon-refresh"></span></button>
</div>
</div>

<div class="row">
<div class="col-md-12">
<hr />
</div>
</div>

<div class="row">
<div class="col-md-12">
</div>
</div>

<div class="row" id="top10Items">
<div class="col-md-6">
<div class="topleft">
<h2 class="sectiontext">Top 10 Items</h2>
<br />
<div id="piechartlegendleft">
<div id="container">
<canvas id="top10ItemsChart" width="800" height="800"></canvas>
</div>
<div id="top10Legend" class="pieLegend"></div>
</div>
</div>
</div>

<div class="col-md-6">
<div class="topright">
<h2 class="sectiontext">Price Compliance</h2>
<div class="graph_container">
<canvas id="priceComplianceBarChart"></canvas>
</div>
</div>
</div>
</div>

<div class="row">
<div class="col-md-6">
<div class="bottomleft">
<h2 class="sectiontext">Forecast/Impact Analysis</h2>
<div class="graph_container">
<canvas id="forecastLineChart"></canvas>
</div>
</div>
</div>

<div class="col-md-6">
<div class="bottomright">
<h2 class="sectiontext">Delivery Performance</h2>
<table id="delperfTable">
. . .
</table>
</div>
</div>
</div>

</div>
</body>
</html>

最佳答案

animation.onComplete 回调中,您可以使用以下代码获取之前的数据集:

// `dataset` here -----------------------------------------┐
// is the current dataset you are working on |
// (since you loop through all of them in your callback) V
var previousDataset = chartInstance.config.data.datasets[dataset._meta[Object.keys(dataset._meta)[0]].controller.index - 1];

现在您可以访问之前的数据集,还可以获取它的值。遵循完整的回调以使其更容易理解:

var forecastOptions = {
tooltips: {
enabled: true
},
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++) {

// We get the previous dataset here
var previousDataset = dataset._meta[Object.keys(dataset._meta)[0]].controller.chart.config.data.datasets[dataset._meta[Object.keys(dataset._meta)[0]].controller.index - 1];

var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
var scale_max = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
ctx.fillStyle = '#444';
var y_pos = model.y - 5;
if ((scale_max - model.y) / scale_max >= 0.93)
y_pos = model.y + 20;

// If the previous dataset is not `undefined` (actually exists) ..
if(typeof previousDataset !== "undefined") {
// We write the data, with the difference with the previous one
ctx.fillText(dataset.data[i] + " (" + (dataset.data[i] - previousDataset.data[i]) + ")", model.x, y_pos);
}
else {
// We only write the data
ctx.fillText(dataset.data[i], model.x, y_pos);
}
}
});
}
}
};

您可以看到此回调正在运行 on this jsFiddle ,这是它的结果:

enter image description here

注意:如果您需要任何小的更改(例如百分比差异),请随时发表评论。

关于javascript - 如何计算一个值并将其放置在 Chart.JS 条形图中的最后一个条形内?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39779510/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com