I have a datetime chart which supposed to show some time intervals. I needed to add some labels to each time interval which shows some data from the array I pass to chart. But the problem is: the more elements I have in the array, the weirder behaviour I get. Datalabels overlapping each other and rendering at the columns they should not be rendered at. I found out that the formatter
triggers multiple times, and I want to find out is there any way to prevent this behaviour and render datalabels only once per data
.
Here's what I'm trying to do:
chart: {
type: 'columnrange',
margin: 0,
inverted: true,
backgroundColor: 'transparent',
events: {
load: function (ctx) {
for (var i = 0; i < data.length; i++) {
this.addSeries({
type: 'columnrange',
grouping: false,
data: [
{
low: i < data.filter(x => x.rowNumber === 4).length
? data.filter(x => x.rowNumber === 4)[i].intervalStart
: Date.UTC(1, 1, 1, 0, 0, 0),
high: i < data.filter(x => x.rowNumber === 4).length
? data.filter(x => x.rowNumber === 4)[i].intervalEnd
: Date.UTC(1, 1, 1, 0, 0, 0),
color: i < data.filter(x => x.rowNumber === 4).length
? (data.filter(x => x.rowNumber === 4)[i].status === 1 ? "#6ebb86" : "#434348")
: "transparent",
dataLabels: {
enabled: true,
verticalAlign: 'middle',
align: 'center',
inside: true,
crop: true,
style: {
fontSize: '14px',
},
formatter: (e) => {
return i < data.filter(x => x.rowNumber === 4).length
? data.filter(x => x.rowNumber === 4)[i]?.dataLabel
: ""
}
}
}
],
borderColor: 'transparent',
});
}
},
},
},
I have found the solution and I want to share it with others.
Instead of writing dataPoints
in the load
function, I decided to move it to plotOptions
-> series
so that from there I could access the series
itself. This is what it looks like:
plotOptions: {
columnrange: {
grouping: false,
pointPadding: -0.2,
states: {
hover: {
borderColor: 'transparent',
},
inactive: {
enabled: false,
},
},
},
series: {
cursor: 'pointer',
point: {
events: {
click: function () {
triggerEditInterval(
this.series.chart.hoverPoint?.options.low!,
this.series.chart.hoverPoint?.options.high!)
},
}
},
dataLabels: {
enabled: true,
verticalAlign: 'middle',
align: 'center',
inside: true,
crop: true,
style: {
fontSize: '14px',
},
formatter: function () {
var actualPoints = this.series.points.filter(p => typeof p.y === 'number'); //getting the list of actual points
if (this.y === actualPoints.find(x => x.y === this.y)?.y) { // if the y of current point exists in our actual points list
if (actualPoints.findIndex(x => x.y === this.y)! === 0) { // check if actual point is first category
return data.find(x => x.intervalEnd === this.y && x.rowNumber === 4)?.dataLabel // return the label of element from our data element with appropriate coordinates and rowNumber for first category
}
else {
return data.find(x => x.intervalEnd === this.y && x.rowNumber === 5)?.dataLabel // else return the element with rowNumber for second category
}
}
}
}
},
},