B. Clay Shannon B. Clay Shannon - 2 months ago 17
Javascript Question

How can I move a label left, paint it black, or remove it (Chart.JS)?

I've got a horizontal bar chart displaying like so:

enter image description here

As the second data value on the bars (1.0, 0.8, etc.) are partially obscured, I would like to do one of the following things, in order of preference:


  1. Move them to the left, so that they are completely visible

  2. Change their font from white to back, so that they are completely visible

  3. Remove them altogether, so that they are completely invisible



The code that is causing them to be written in the first (second?) place is this:

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._me
[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));
}
});
}
});


...but I don't see just where there I can manipulate those values as desired.

For context and full disclosure, here is all the code for the 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';

chartInstance.data.datasets.forEach(function (dataset) {
for (var i = 0; i < dataset.data.length; i++) {
var model = dataset._meta[Object.keys(dataset._met
[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", "Cost
Fruit and Produce",
"Get Fresh Sales",
"Loffredo East", "Loffredo West", "Paragon", "Piazz
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
});


I am using Chart.js version 2.2.2

Answer

1st solution : Move to the left

In your plugin, set the context textAlign property to right if it is the second dataset :

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;

        // If it is the second dataset (red color) ..
        if (dataset._meta[0].controller.index== 1) {
            // .. align to the right
            ctx.textAlign ="right";
            // .. and write it at the right bound of the chart
            ctx.fillText(parseFloat(dataset.data[i]).toFixed(2) + "%", (model.x - 2), (model.y + model.height / 3));

           // This looks like it has been moved a bit to the left
        }

        // Else ..
        else {
            // .. write as usual
            ctx.fillText(parseFloat(dataset.data[i]).toFixed(2) + "%", ((model.base + model.x) / 2), (model.y + model.height / 3));
        }
    }
});

Check the result on this jsFiddle.


2nd solution : Put the text in black

In your plugin, set the context fillStyle property to the color you want (#000 for instance) :

afterDraw: function(chartInstance) {
    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';

    // Here :
    ctx.fillStyle = "#000";

    chartInstance.data.datasets.forEach(function(dataset) {
        // ...
    });
});

Check the result on this jsFiddle.


3rd solution : Remove it, pure and simple

Add a condition in your plugin to check which dataset you are currently working on :

chartInstance.data.datasets.forEach(function(dataset) {
    for (var i = 0; i < dataset.data.length; i++) {

        // If it is the second dataset (red color), we break out of the loop
        if (dataset._meta[0].controller.index == 1) break;

        var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;

        ctx.fillText(parseFloat(dataset.data[i]).toFixed(2) + "%", ((model.base + model.x) / 2), (model.y + model.height / 3));
    }
});

Check the result on this jsFiddle.