Knowledge Base Article

Bar Chart - Prevent bars from hiding the value label text

When creating a bar chart and formatting it to include "Values",  you might find out that the bars cover their values. The following (widget) code manipulates the bars' width and label position:

const labelWidth = 25 + 5 // 5 is the space between the label and the bar

widget.on('domready', function(widget) {
try {
console.log('DOM Ready script starting (wid=' + widget.oid + ')');

// Get plot width
plotWidth = parseInt(widget.chart[0].getElementsByClassName('highcharts-plot-border')[0].getAttribute('width'));

// Find Widest bar
maxBarWidth = -1;
widget.chart[0].getElementsByClassName('highcharts-series','highcharts-bar-series').forEach(bar => {
bar.childNodes.forEach(rect => {
if (parseInt(rect.getAttribute('height')) > maxBarWidth)
maxBarWidth = parseInt(rect.getAttribute('height'))
})
})

if (maxBarWidth == -1) return;

// Check if we require adjustment
if (plotWidth - maxBarWidth > labelWidth) return;

ratio = (maxBarWidth - labelWidth) / maxBarWidth;

// Adjust Bar height and location
barsArray = widget.chart[0].getElementsByClassName('highcharts-series','highcharts-bar-series');
labelsArray = widget.chart[0].getElementsByClassName('highcharts-data-labels');

for (let seriesNum = 0; seriesNum < barsArray.length; seriesNum++) {
for (let barNum = 0; barNum < barsArray[seriesNum].childNodes.length; barNum++) {
currentWidth = parseInt(barsArray[seriesNum].childNodes[barNum].getAttribute('height'));
currentY = parseInt(barsArray[seriesNum].childNodes[barNum].getAttribute('y'));
transformLabel = labelsArray[seriesNum].childNodes[barNum].getAttribute('transform')

// Calculate offset
offset = Math.round(currentWidth * (1-ratio))

// Adjust bars
barsArray[seriesNum].childNodes[barNum].setAttribute('height',currentWidth-offset)
barsArray[seriesNum].childNodes[barNum].setAttribute('y',currentY+offset)

// Adjust labels
newLabel = 'translate(' + (currentWidth - offset) + ',' + transformLabel.split(',')[1]
labelsArray[seriesNum].childNodes[barNum].setAttribute('transform',newLabel)
}
}
}
catch (error) {
console.error(error);
}
finally {
console.log('DOM Ready script complete (wid=' + widget.oid + ')');
}
});
Before After
Updated 03-25-2022

9 Comments

    • Ophir_Buchman's avatar
      Ophir_Buchman
      Data Integration

      Hi cartercjb 

      In 'domready' - Perform the following:

      $('.highcharts-series.highcharts-series-1')[0].childNodes.forEach(item => item.setAttribute('opacity',0.3))

       

       

  • BIQ's avatar
    BIQ
    Cloud Apps

    How can we get this code to work on column charts as well? 

  • How this code could also work for negative bar charts? For us, it's working fine for positive values, but for negative values, it does not.

    Example:

    We would like that the numbers once inside the bar would be white as the third bar is and once they out they would be gray the first bar is.

  • Hello! This script doesn't seem to work on stacked bar charts. On regular (non-stacked) bar charts it mostly works as expected, and I can adjust the number in the first line to adjust how much space there is. However, when I try the same script on stacked bar charts, it doesn't seem to have any effect, regardless of which number I put in the first line. 

    I bet it's due to the break-by splitting the bars into multiple stacked bars, and the script is only designed to shorten single bars. Is there a way to modify the script so it works on stacked bars instead?

    • TriAnthony's avatar
      TriAnthony
      Admin

      Hi fabricio_fta and Jake_Raz, please try this script below. This should work for:

      • all Cartesian charts (Column, Bar, Line, and Area charts),
      • negative values,
      • single and multiple series (classic or stacked, using Break By or multiple values).

       

      /***  This script is for increasing the y-axis max value by adding a percent of the highest value in the series to the y-axis max value.
      Similarly, in cases where the minimum value is negative, it also decreases the y-axis min value by subtracting a percent of the lowest value in the series from the y-axis min value. ***/
      
      //Set the offset percent to add/subtract to/from the y-axis max/min value here
      var percentToAdd = 20;
      
      widget.on('processresult', function(se,ev){
      
      	var numberOfSeries = ev.result.series.length;
      
      	var seriesData = [];
      
      	var dataPoints = [];
      
      	for(i=0; i < numberOfSeries; i++) {
      
      		seriesData[i] = ev.result.series[i].data;
      
      		var numOfDataPoints = seriesData[i].length;
      
      		if(widget.subtype.includes('stacked')) {
      
      			if(i==0) {
      				for(j=0; j < numOfDataPoints; j++) {
      
      					var dataToPush = seriesData[i][j].y;
      
      					dataPoints.push(dataToPush);
      				}
      			}
      			else {
      				for(j=0; j < numOfDataPoints; j++) {
      
      					dataPoints[j] = dataPoints[j] + seriesData[i][j].y;
      				}
      			}
      		}
      
      		else if(widget.subtype.includes('classic') || widget.subtype.includes('basic')) {
      
      			for(j=0; j < numOfDataPoints; j++) {
      
      				var dataToPush = seriesData[i][j].y;
      
      				dataPoints.push(dataToPush);
      			}
      		}
      	}
      
      	var maxValue = Math.max.apply(Math, dataPoints);
      
      	var minValue = Math.min.apply(Math, dataPoints);
      
      
      	if(ev.result.yAxis[0].max <= 0) {
      		ev.result.yAxis[0].max = 0
      	}
      	else {
      		ev.result.yAxis[0].max = maxValue * (1 + percentToAdd/100);
      	}
      
      	if(ev.result.yAxis[0].min >= 0) {
      		ev.result.yAxis[0].min = 0;
      	}
      	else {
      		ev.result.yAxis[0].min = minValue * (1 + percentToAdd/100);
      	}
      
      
      })