I have been creating a heatmap feature for my own dashboard which will show heatmaps across the pages.
In the frontend script I have been saving them like this by getting these needed attributes
function clickHandler(e) {
let target = e.target || e.srcElement;
const
rect = target.getBoundingClientRect(),
elementX = e.clientX - rect.left,
elementY = e.clientY - rect.top,
elementWidth = rect.width,
elementHeight = rect.height;
//
const
fullPageX = e.pageX,
fullPageY = e.pageY,
body = document.body,
html = document.documentElement,
width = window.innerWidth,
height = Math.max(body.scrollHeight, body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight);
//
rrweb.record.addCustomEvent("click", {
element: {
x: elementX,
y: elementY,
elementWidth,
elementHeight,
},
fullpage: {
x: fullPageX,
y: fullPageY,
innerWidth: width,
innerHeight: height,
},
});
console.log(elementX, elementY, width, height, fullPageX, fullPageY, elementWidth, elementHeight);
}
I have been saving them into database so I can retrieve them from the api.
Example of a retrieved data.
{
"x_coord": 629,
"y_coord": 1201,
"height": 959,
"width": 1920,
"element_width": 498,
"element_height": 508,
"x_element": 466.0279541015625,
"y_element": 85.62030029296875,
"page_height": 5781,
"click_count": "1"
}
{
"x_coord": -500,
"y_coord": 1227,
"height": 959,
"width": 1920,
"element_width": 115,
"element_height": 83,
"x_element": 63.191253662109375,
"y_element": 40.5150146484375,
"page_height": 5781,
"click_count": "1"
}
I group them by
GROUP BY x_coord, y_coord, width, height, element_width, element_height,x_element, y_element,page_height
The problem lies with scaling the x,y values when the users are on a different screen size resolution
I have been following these answers to implement the saving of the metrics
How to recalculate x,y coordinates based on screensize But it does not seem to correctly work when I am trying to scale the x y on a different size.
The frontend part is made with angular 8 where we used heatmap.js to construct the heatmap, the container where is shown is not full width because I have sidenav and other elements but we can take it as it will be 800px wide. What I need to do is to scale the backgroundImage (width:~1520px and height is the full page height which we use a bot to make it ~8000px with the container on my dashboard, and then construct the coordinates corresponding to that container.
when users screen is the same with screenshot the points are shown correctly but when the screen is with size lower or higher than the screenshot the points shifts by the X value and Y value.
What am i missing?
Scaling Logic =>
let width = coordinates[i].width;
let height = coordinates[i].page_height;
let x = width / 2 + coordinates[i].x_coord;
let y = coordinates[i].y_coord;
let widthRatio = nativeElement.clientWidth / width;
let heightRatio = nativeElement.clientHeight / height;
userData.push({
x: Math.round(x * widthRatio),
y: Math.round(y * heightRatio),
value: parseInt(coordinates[i].click_count),
});
2
Answers
start by determining the actual size of the area where you want to display the heatmap, which could be different from the full screen due to elements like a sidebar or margins assign these
containerWidth
andcontainerHeight
.loop through each set of coordinates you have collected. For each set calculate how much smaller or larger the heatmap display area is compared to the original size where the click was recorded this is done by comparing the display area’s width and height to the original recorded values, creating a width ratio and a height ratio.
apply these ratios to the original
x
andy
coordinates to scale them to fit the new size. Essentially, you’re resizing the click points so they appear in the correct location on the smaller or larger display.I would use a D3 scale for that:
scale
is a function that maps a value in a domain (A) (the set of possible input) to another value in a range (B) (e.g the set of possible output). e.g.,Let’s plot the value
5
on different x axes: