cancel
Showing results for 
Search instead for 
Did you mean: 

Column Chart - Prevent bars from hiding the value label text

Ophir_Buchman
Sisense Team Member
Sisense Team Member

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

const labelHeight = 25

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

// Get plot height
plotHeight = parseInt(widget.chart[0].getElementsByClassName('highcharts-plot-border')[0].getAttribute('height'));
if (plotHeight < labelHeight * 3) return;

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

if (maxColumnHeight == -1) return;

// Check if we require adjustment
if (plotHeight - maxColumnHeight > labelHeight) return;

ratio = (maxColumnHeight - labelHeight) / maxColumnHeight;

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

for (let seriesNum = 0; seriesNum < columnsArray.length; seriesNum++) {
for (let columnNum = 0; columnNum < columnsArray[seriesNum].childNodes.length; columnNum++) {

currentHeight = parseInt(columnsArray[seriesNum].childNodes[columnNum].getAttribute('height'));
currentY = parseInt(columnsArray[seriesNum].childNodes[columnNum].getAttribute('y'));
transformLabel = labelsArray[seriesNum].childNodes[columnNum].getAttribute('transform')

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

// Adjust columns
columnsArray[seriesNum].childNodes[columnNum].setAttribute('height',currentHeight-offset)
columnsArray[seriesNum].childNodes[columnNum].setAttribute('y',currentY+offset)

// Adjust labels
newLabel = transformLabel.split(',')[0] + ',' + (currentY+offset-labelHeight) + ')';
labelsArray[seriesNum].childNodes[columnNum].setAttribute('transform',newLabel)
}
}
}
catch (error) {
console.error(error);
}
finally {
console.log('DOM Ready script complete (wid=' + widget.oid + ')');
}
});

 

Before After
Ophir_Buchman_0-1648034803433.png Ophir_Buchman_1-1648034829612.png
1 REPLY 1

Jake_Raz
8 - Cloud Apps
8 - Cloud Apps

I've been using this script to great effect, but I just realized that it doesn't seem to be working the way I imagined. I had assumed the script was dynamically adjusting the "max" end of the scale so the labels naturally had enough room to display. Now that I'm looking at this again, though, it looks like I was wrong. You quite clearly said it "manipulates the columns' height and label position". I didn't realize until just now when I noticed that, in the "after" screenshot, the scale is exactly the same (max of 200).

This script is fine if you're going to be hiding the scale, but if you want or need to show the scale for some reason, then this might not be ideal because now the lengths of the bars don't match the scale. For example, the "199" bars show far lower than they should compared to where "200" is on the scale. Same with "160" (it's well below the half-way point between 100 and 200).

Is it possible to create a script that does what I was originally imagining? That is, dynamically adjusting the max scale? Using the built-in "auto" option is what leads to the covered-up values, so I just need a way to add an offset or buffer to that. (In the past I would just manually set the scale, but this isn't ideal since it doesn't update in response to different data.)