I'm working on a hobby project similar to markup.io where you can load in any website and annotate it. I can't figure out how to add an annotation that behaves like it does in markup.io:
From what I can see they place an absolute positioned div inside the element that you clicked on. From my understanding by reading the docs that div would position itself based on the closest positioned ancestor. How would you calculate the correct top and left values to position the annotation to where the user clicked? Is there a better way to do this?
I'm using React if that matters.
Things that I have tried:
<div style="width:0px; height:0px; position:relative;">
<div style="width:50px;height:50px;position:absolute; ">this is the annotation </div>
</div>
Problem: This would mess with the page layout because of the relative positioned div that is not ignored by the document flow.
Problem: Whenever the user would scroll or resize the window the annotation would need to be redrawn at the new position of the element. I used getBoundintClientRect to get the new position and this would cause a reflow and caused the whole website to have severe perfomance issues when dealing with 100+ annotations.
Hopefully someone can point me in the right direction!
The general idea is as follows:
// In my case I put the webpage in an Iframe. If this is your own page
// you can just use document.
iframe.contentWindow.document.addEventListener(
'click',
(e: MouseEvent) => {
// step 1: find the parent.
let parent = e.target.parentElement;
let computedStyle = window.getComputedStyle(parent);
// step 2 & 3: Look up the first positioned element and make this the
// the element that you're going to append your badge/annotation to.
while (
computedStyle.position === 'static' &&
parent.parentElement !== null
) {
parent = parent.parentElement;
computedStyle = window.getComputedStyle(parent);
}
// style the annotation the way you want to
const badge = document.createElement('div');
const { top, left } = parent.getBoundingClientRect();
badge.style.position = 'absolute';
// step 4 and 5 get the mouse position through e.clientX and Y and
// subtract the appropriate value like below to place it exactly at the mouse position
badge.style.top = `${e.clientY - top - 5}px`;
badge.style.left = `${e.clientX - left - 5}px`;
badge.style.backgroundColor = 'red';
badge.style.width = '10px';
badge.style.height = '10px';
badge.style.borderRadius = '50%';
badge.style.zIndex = '9999';
parent.appendChild(badge);
}
);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.