My goal is to have one or more PNG images displayed on top of a line chart HighCharts with a color gradient as shown below:
I have tried the following code, but the image seems to be buried behind the chart.
Also I am not understanding how to correctly position the image (e.g. I had to use the value 400
to get the image to be positioned at the 200 marker - chart.plotTop + chart.yAxis[0].toPixels(400)
)
document.addEventListener('DOMContentLoaded', function () {
var temperatures = [
[Date.UTC(2024, 8, 1), 20], // September 1st
[Date.UTC(2024, 8, 2), 39],
[Date.UTC(2024, 8, 3), 58],
[Date.UTC(2024, 8, 4), 78],
[Date.UTC(2024, 8, 5), 95],
[Date.UTC(2024, 8, 6), 110],
[Date.UTC(2024, 8, 7), 125],
[Date.UTC(2024, 8, 8), 142],
[Date.UTC(2024, 8, 9), 160],
[Date.UTC(2024, 8, 10), 180],
[Date.UTC(2024, 8, 11), 200],
[Date.UTC(2024, 8, 12), 219],
[Date.UTC(2024, 8, 13), 238],
[Date.UTC(2024, 8, 14), 258],
[Date.UTC(2024, 8, 15), 275],
[Date.UTC(2024, 8, 16), 290],
[Date.UTC(2024, 8, 17), 315],
[Date.UTC(2024, 8, 18), 332],
[Date.UTC(2024, 8, 19), 350],
[Date.UTC(2024, 8, 20), 370]
];
// Options for the chart
var options = {
chart: {
type: 'line',
plotBackgroundColor: {
linearGradient: [0, 0, 0, 400],
stops: [
[0, 'green'],
[1, 'yellow']
]
},
plotBackgroundImage: null
},
title: {
text: 'Temperature Line Chart'
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: {
month: '%b %e'
},
min: Date.UTC(2024, 8, 1), // Start from September 1st
max: Date.UTC(2024, 8, 20),
},
yAxis: {
title: {
text: 'Temperature'
}
},
plotOptions: {
series: {
marker: {
enabled: false // Disable markers on data points
}
}
},
series: [{
name: 'Temperature',
data: temperatures
}]
};
var chart = Highcharts.chart('container', options);
Highcharts.addEvent(Highcharts.Chart, 'render', function() {
chart.renderer.image('https://cdn-icons-png.flaticon.com/64/8445/8445275.png', // URL of the PNG image
chart.plotLeft + chart.xAxis[0].toPixels(Date.UTC(2024, 8, 8)),
chart.plotTop + chart.yAxis[0].toPixels(400),
64, 64
).add().toFront();
});
When in comes to the picture behind the chart, using toFront()
is one choice, and zIndex
also works well.
In case of the positioning, the toPixels()
method uses the axis position as its argument, and you don't have to add plotTop or plotLeft. However, to position image correctly, you should also consider it's height and width.
Here's an improved version of the code where the image is added in the render() method, which helps make it responsive:
let temperatures = [
[Date.UTC(2024, 8, 1), 20],
[Date.UTC(2024, 8, 2), 39],
[Date.UTC(2024, 8, 3), 58],
[Date.UTC(2024, 8, 4), 78],
[Date.UTC(2024, 8, 5), 95],
[Date.UTC(2024, 8, 6), 110],
[Date.UTC(2024, 8, 7), 125],
[Date.UTC(2024, 8, 8), 142],
[Date.UTC(2024, 8, 9), 160],
[Date.UTC(2024, 8, 10), 180],
[Date.UTC(2024, 8, 11), 200],
[Date.UTC(2024, 8, 12), 219],
[Date.UTC(2024, 8, 13), 238],
[Date.UTC(2024, 8, 14), 258],
[Date.UTC(2024, 8, 15), 275],
[Date.UTC(2024, 8, 16), 290],
[Date.UTC(2024, 8, 17), 315],
[Date.UTC(2024, 8, 18), 332],
[Date.UTC(2024, 8, 19), 350],
[Date.UTC(2024, 8, 20), 370]
];
Highcharts.chart('container', {
chart: {
events: {
render() {
let chart = this,
imageSize = 64
if (!chart.myImage) {
chart.myImage = chart.renderer.image('https://cdn-icons-png.flaticon.com/64/8445/8445275.png', chart.xAxis[0].toPixels(Date.UTC(2024, 8, 11)) - imageSize / 2,
chart.yAxis[0].toPixels(200) - imageSize / 2,
imageSize, imageSize
).add();
}
chart.myImage.attr({
x: chart.xAxis[0].toPixels(Date.UTC(2024, 8, 11)) - imageSize / 2,
y: chart.yAxis[0].toPixels(200) - imageSize / 2,
zIndex: 100
})
}
},
type: 'line',
plotBackgroundColor: {
linearGradient: [0, 0, 0, 400],
stops: [
[0, 'green'],
[1, 'yellow']
]
},
plotBackgroundImage: null
},
title: {
text: 'Temperature Line Chart'
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: {
month: '%b %e'
},
min: Date.UTC(2024, 8, 1),
max: Date.UTC(2024, 8, 20),
},
yAxis: {
title: {
text: 'Temperature'
}
},
plotOptions: {
series: {
marker: {
enabled: false
}
}
},
series: [{
name: 'Temperature',
data: temperatures
}]
});